我想从 Java 直接(或间接)查询 Windows Vista 搜索服务。
我知道可以使用 search-ms: 协议进行查询,但我想在应用程序中使用结果。
我在Windows Search API中找到了很好的信息, 但没有与 Java 相关的信息。
我会将提供有关如何实现此目标的有用和明确信息的答案标记为已接受。
提前致谢。
编辑
在我将其标记为已接受之前,是否有人有 JACOB 样本?:)
我想从 Java 直接(或间接)查询 Windows Vista 搜索服务。
我知道可以使用 search-ms: 协议进行查询,但我想在应用程序中使用结果。
我在Windows Search API中找到了很好的信息, 但没有与 Java 相关的信息。
我会将提供有关如何实现此目标的有用和明确信息的答案标记为已接受。
提前致谢。
编辑
在我将其标记为已接受之前,是否有人有 JACOB 样本?:)
您可能想查看其中一种 Java-COM 集成技术。我曾亲自与 JACOB (JAva COM Bridge) 合作过:
这相当麻烦(想想只使用反射),但为我完成了工作(快速概念证明,从 Java 中访问 MapPoint)。
我知道的唯一其他此类技术是 Jawin,但我没有任何个人经验:
2009 年 4 月 26 日更新: 为了它,我对 Microsoft Windows 搜索进行了更多研究,并找到了一种使用 OLE DB 与其集成的简单方法。这是我编写的一些代码作为概念证明:
public static void main(String[] args) {
DispatchPtr connection = null;
DispatchPtr results = null;
try {
Ole32.CoInitialize();
connection = new DispatchPtr("ADODB.Connection");
connection.invoke("Open",
"Provider=Search.CollatorDSO;" +
"Extended Properties='Application=Windows';");
results = (DispatchPtr)connection.invoke("Execute",
"select System.Title, System.Comment, System.ItemName, System.ItemUrl, System.FileExtension, System.ItemDate, System.MimeType " +
"from SystemIndex " +
"where contains('Foo')");
int count = 0;
while(!((Boolean)results.get("EOF")).booleanValue()) {
++ count;
DispatchPtr fields = (DispatchPtr)results.get("Fields");
int numFields = ((Integer)fields.get("Count")).intValue();
for (int i = 0; i < numFields; ++ i) {
DispatchPtr item =
(DispatchPtr)fields.get("Item", new Integer(i));
System.out.println(
item.get("Name") + ": " + item.get("Value"));
}
System.out.println();
results.invoke("MoveNext");
}
System.out.println("\nCount:" + count);
} catch (COMException e) {
e.printStackTrace();
} finally {
try {
results.invoke("Close");
} catch (COMException e) {
e.printStackTrace();
}
try {
connection.invoke("Close");
} catch (COMException e) {
e.printStackTrace();
}
try {
Ole32.CoUninitialize();
} catch (COMException e) {
e.printStackTrace();
}
}
}
要编译它,您需要确保 JAWIN JAR 在您的类路径中,并且 jawin.dll 在您的路径中(或 java.library.path 系统属性)。此代码仅打开到本地 Windows 桌面搜索索引的 ADO 连接,使用关键字“Foo”查询文档,并在结果文档上打印出一些关键属性。
如果您有任何问题,或者需要我澄清任何事情,请告诉我。
2009 年 4 月 27 日更新: 我也尝试在 JACOB 中实现相同的功能,并将做一些基准测试来比较两者之间的性能差异。我可能在 JACOB 中做错了什么,但它似乎一直在使用 10 倍以上的内存。如果我有时间的话,我也会研究 jcom 和 com4j 的实现,并尝试找出一些我认为是由于某处缺乏线程安全而导致的怪癖。我什至可以尝试基于 JNI 的解决方案。我希望在 6-8 周内完成所有工作。
2009 年4 月 28 日更新: 这只是针对那些一直在关注和好奇的人的更新。事实证明没有线程问题,我只需要显式关闭我的数据库资源,因为 OLE DB 连接可能是在操作系统级别汇集的(我可能应该已经关闭了连接......)。我认为我不会对此进行任何进一步的更新。如果有人遇到任何问题,请告诉我。
2009 年 5 月 1 日更新: 根据 Oscar 的要求添加了 JACOB 示例。从 COM 的角度来看,这经历了完全相同的调用序列,只是使用了 JACOB。虽然最近 JACOB 确实得到了更积极的工作,但我也注意到它非常消耗内存(使用的内存是 Jawin 版本的 10 倍)
public static void main(String[] args) {
Dispatch connection = null;
Dispatch results = null;
try {
connection = new Dispatch("ADODB.Connection");
Dispatch.call(connection, "Open",
"Provider=Search.CollatorDSO;Extended Properties='Application=Windows';");
results = Dispatch.call(connection, "Execute",
"select System.Title, System.Comment, System.ItemName, System.ItemUrl, System.FileExtension, System.ItemDate, System.MimeType " +
"from SystemIndex " +
"where contains('Foo')").toDispatch();
int count = 0;
while(!Dispatch.get(results, "EOF").getBoolean()) {
++ count;
Dispatch fields = Dispatch.get(results, "Fields").toDispatch();
int numFields = Dispatch.get(fields, "Count").getInt();
for (int i = 0; i < numFields; ++ i) {
Dispatch item =
Dispatch.call(fields, "Item", new Integer(i)).
toDispatch();
System.out.println(
Dispatch.get(item, "Name") + ": " +
Dispatch.get(item, "Value"));
}
System.out.println();
Dispatch.call(results, "MoveNext");
}
} finally {
try {
Dispatch.call(results, "Close");
} catch (JacobException e) {
e.printStackTrace();
}
try {
Dispatch.call(connection, "Close");
} catch (JacobException e) {
e.printStackTrace();
}
}
}
正如这里的一些帖子建议您可以使用商业或免费框架(如 JACOB、JNBridge、J-Integra 等)在 Java 和 .NET 或 COM 之间架起一座桥梁。实际上,我曾与这些第三方之一合作过(一个昂贵的 :-) ) 而且我必须说我会尽我所能避免以后再犯这个错误。原因是它涉及许多你无法真正调试的“巫毒”东西,当出现问题时理解问题是非常复杂的。
我建议您实施的解决方案是创建一个简单的 .NET 应用程序,该应用程序对 Windows 搜索 API 进行实际调用。这样做之后,您需要在该组件和您的 Java 代码之间建立一个通信通道。这可以通过多种方式完成,例如通过向应用程序定期提取的小型数据库发送消息。或者在机器 IIS(如果存在)上注册此组件并公开简单的 WS API 以与之通信。
我知道这听起来可能很麻烦,但明显的优势是:a)您使用 Windows 搜索 API 使用它理解的语言(.NET 或 COM)进行通信,b)您控制所有应用程序路径。
有什么理由不能只使用命令的结果Runtime.exec()
来查询search-ms
并读取BufferedReader
命令的结果?例如:
public class ExecTest {
public static void main(String[] args) throws IOException {
Process result = Runtime.getRuntime().exec("search-ms:query=microsoft&");
BufferedReader output = new BufferedReader(new InputStreamReader(result.getInputStream()));
StringBuffer outputSB = new StringBuffer(40000);
String s = null;
while ((s = output.readLine()) != null) {
outputSB.append(s + "\n");
System.out.println(s);
}
String result = output.toString();
}
}
有几个库用于从 java 调用 COM 对象,一些是开源的(但它们的学习曲线更高)一些是闭源的并且具有更快的学习曲线。一个封闭源代码的例子是EZCom。商业的也倾向于专注于从 Windows 调用 java,这是我在开源中从未见过的。
在你的情况下,我建议你做的是在你自己的 .NET 类中调用(我想使用 C#,因为它最接近 Java,而不涉及有争议的 J#),并专注于与 .NET dll 的互操作性. 这样windows编程就更容易了,windows和java的接口也更简单了。
如果您正在寻找如何使用 java com 库,MSDN 是错误的地方。但是 MSDN 将帮助您从 .NET 中编写所需的内容,然后查看 com 库教程,了解如何从 .NET 对象中调用您需要的一两个方法。
编辑:
鉴于答案中有关使用 Web 服务的讨论,您可以(并且可能会有更好的运气)构建一个调用嵌入式 Java Web 服务器的小型 .NET 应用程序,而不是尝试让 .NET 具有嵌入式 Web 服务,并拥有java 是调用的消费者。对于嵌入式 Web 服务器,我的研究表明Winstone非常好。不是最小的,但更灵活。
使其工作的方法是从 java 启动 .NET 应用程序,并让 .NET 应用程序在计时器或循环上调用 Web 服务以查看是否有请求,如果有,处理并发送响应。