【问题标题】:XML: MSXML Not InstalledXML:未安装 MSXML
【发布时间】:2013-12-27 00:59:37
【问题描述】:

使用此代码获取站点的 rss。此代码适用于我的计算机和许多其他计算机。但在某些计算机(Windows XP 或 7)中,我收到此错误:MSXML Not Installed

我该如何解决这个问题?怎么了?

代码如下:

procedure My_Thread.Execute;
var
  http                 : tidhttp;
  strm                 : tmemorystream;
  str,sTitle,  sDec ,er : string;
  StartItemNode        : IXMLNode;
  ANode                : IXMLNode;
  XMLDoc               : IXMLDocument;

begin
  http := tidhttp.Create();
  strm := tmemorystream.Create;
    try
      http.Get('http://www.sample.com/rss.xml',strm);     //Download the RSS file
      SetString(str,PANSIChar(strm.Memory),strm.Size);

      XMLDoc :=  LoadXMLData(str);

      StartItemNode := XMLDoc.DocumentElement.ChildNodes.First.ChildNodes.FindNode('item');
      ANode         := StartItemNode;

      i := 0;
      repeat
        inc(i);
        sTitle    := ANode.ChildNodes['title'].Text;
        sDec       := ANode.ChildNodes['description'].Text;
        Synchronize(procedure begin            //Synchronize? I'm using threads
          case I of
            1: begin
                 main_frm.edit1.text := sTitle; //main_frm is my form
                 main_frm.edit2.text := sDec;
               end;
            2: begin
                 main_frm.edit3.text := sTitle;
                 main_frm.edit4.text := sDec;
               end;
            3: begin
                 main_frm.edit5.text := sTitle;
                 main_frm.edit6.text := sDec;
               end;
          end;
          ANode := ANode.NextSibling;
        end);
      until ANode = nil;

      http.Free;
      strm.Free;

    except
      on E: Exception do
        begin
          er := e.Message;
          Synchronize(procedure begin
            ShowMessage(er);
          end);
        end;
    end;
end;

如您所见,我正在使用线程。所以需要Synchronize

【问题讨论】:

  • 您从异常中得到了该消息,对吧?调试器会中断您的程序并告诉您异常的确切来源,不是吗?所以调试它。至少,在您的问题中包含异常的来源。
  • 这是一个完整的旁白,但Dec 是一个用于减少整数的函数(以System 为单位)。在这里,您声明了一个字符串变量Dec,它隐藏了该函数。这是一种不好的做法,尤其是对于像 dec 这样的常用函数 - 您应该为变量使用唯一的名称。
  • @J... 已修复。谢谢
  • 我认为您需要在使用 MSXML 之前在线程中调用“CoInitializeEx”。但是在一些电脑上工作..,不知道..
  • ShowMessage 不是远程调试工具。使用 MadExcept 收集真实的异常信息。除非您知道如何解决触发异常的问题,否则不要捕获异常。

标签: xml delphi xml-parsing


【解决方案1】:

在 Windows 上,TXMLDocument 默认使用 MSXML,它使用 COM 对象。您的线程在加载 XML 之前没有调用 CoInitialize/Ex(),因此 COM 无法实例化 IXMLDocument 尝试在内部创建的任何 MSXML COM 对象(它尝试创建多个 COM 对象以发现实际的 MSXML 版本安装)。您看到的错误消息意味着所有 MSXML COM 对象都无法实例化。

您必须在每个访问 COM 对象的线程上下文中调用 CoInitialize/Ex(),例如:

procedure My_Thread.Execute;
var
  ...
begin
  CoInitialize(nil);
  try
    ...
    XMLDoc := LoadXMLData(str);
    try
     ...
    finally
      // Since CoInitialize() and CoUninitialize() are being called in the same
      // method as local COM interface variables, it is very important to release
      // the COM interfaces before calling CoUninitialize(), do not just let them
      // release automatically when they go out of scope, as that will be too late...
      StartItemNode := nil;
      ANode := nil;
      XMLDoc := nil;
    end;
    ...
  finally
    CoUninitialize;
  end;
end;

更新:如果你不想依赖这个:你可以使用你选择的不同的 XML 库,你不必使用 MSXML:

Using the Document Object Model

选择 XML 供应商

当您构建应用程序时,RAD Studio 使用默认的内置 XML 供应商 MSXML

如果您没有指定不同的 XML 供应商,您的应用程序在 Windows 以外的其他平台上不支持 XML,并且当您在其他平台上运行您的应用程序时会看到运行时异常。对于跨平台应用程序,OmniXML 是目前最好的选择,因为它显示出比 ADOM 更好的性能。

要选择不同的 XML 供应商,add a reference 将供应商的单元转换为您使用 RTL XML 功能的单元,例如 TXMLDocument 类。如果您添加多个 XML 供应商单元,则引用的第一个单元将用作 XML 供应商。如果您需要覆盖此行为,请将 DefaultDOMVendor 全局变量的值更改为您要使用的 XML 供应商的全局变量。

注意:您可以在上面的List of Built-in XML Vendors 中查找每个 XML 供应商的单位和全局变量。

当您使用TXMLDocument 组件时,您可以使用其DOMVendor 属性选择一个XML 供应商。当您更改DOMVendor 的值时,使用该组件的单元被配置为使用指定的XML 供应商,因此您无需手动更改单元引用或DefaultDOMVendor 全局变量。

【讨论】:

  • 关于释放 COM 接口的评论真的很有趣。这是否也适用于通过导入 WSDL 生成的接口?
  • @LucasSteffen 它仅适用于专门用于 COM 对象的接口。 Delphi 接口通常不依赖于 COM(尽管 Delphi 的 IInterface 是仿照 COM 的 IUnknown 建模的)。 AFAIK,Delphi 的 WSDL 框架不是基于 COM 的。
  • 为什么没有人分享使用条款中要求的单位以了解他们代码中的内容???
【解决方案2】:

我在我的一个 Delphi 项目中遇到了同样的问题,但我使用了 IdThreadComponent 而不是 Thread 对象。我的问题是: 文档:= NewXMLDocument; 我从线程运行方法中删除了这一行,并将其放在调用线程之前,如下所示: 文档 := NewXMLDocument; IdThreadComponent1.Start;

【讨论】:

  • 之后我又看到了同样的问题。当我调用一个过程来保存我的 xml 文件时,发生了新问题。最后我用这一行解决了这个问题:IdThreadComponent1.Synchronize(SaveXML);
  • 那是因为您在主 UI 线程中创建 XMLDocument,所以默认情况下只有该线程可以使用它。 MSXML 的 COM 对象不使用多线程单元模型,因此您必须手动跨线程边界封送其 COM 接口。最好只在将使用它的同一线程中创建 XMLDocument。只需确保事先在该线程中初始化 COM 库
【解决方案3】:

MSXMLS 需要先安装在 servicePack2 for XP MSXML 4.0 Service Pack 2 (Microsoft XML Core Services) Microsoft Core XML Services (MSXML) 6.0 与 windows 7 相同。 再见

【讨论】:

  • 但是当我在表单中使用TXMLDocument 而不使用线程时,它工作正常。为什么?
  • 也许它们不是线程安全的。您可能会注意做一个关键部分..真的需要为此使用线程吗?我认为您的内存中有数据,只需将其放入表单中即可!再见
  • 我删除了线程。有效。但我需要在线程中使用它:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-12
  • 1970-01-01
  • 2014-04-17
  • 1970-01-01
  • 2022-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多