【问题标题】:How can I easily use a COM component in Native Visual C++如何在 Native Visual C++ 中轻松使用 COM 组件
【发布时间】:2010-11-11 20:37:05
【问题描述】:

我正在尝试在 VisualStudio ´05 中构建一个使用 COM 组件的应用程序 在本机 C++ 中。 MSDN 中对事物的原生和托管描述的混合完全破坏了我的 脑。 (我认为 MSDN 在这方面是一团糟) 我需要一个简短的本机 C++ 代码示例来加载我的组件 并使其可用。 我同意编译器创建包装器等。

请不要建议我使用基于对话框的 MFC 示例,因为 它不适用于此组件,并且本身就是一个巨大的 一堆c...代码。

这可能是本机 com 与托管 com 的问题吗?

我完全迷路了,请给我一些方向......

编辑:感谢所有帮助。 我的问题是我只有一个注册的dll(实际上是OCX,见下文) .我(个人)知道 界面应该是什么样子,但我如何告诉我的程序? 没有定义的标题 我可以使用的接口的 ID。但我读到 c++ 编译器 可以为我提取和包装它。有人知道这是怎么做到的吗?

澄清:我只有 OCX 和文档中的线索 组件,它应该公开哪些方法。

【问题讨论】:

    标签: c++ visual-c++ com activex


    【解决方案1】:

    我赞赏您使用本机 C++ 处理 COM 的努力 - 您需要经历痛苦才能真正欣赏当今豪华(托管)的开发环境 :)

    在世界(和我)还年轻的时候,Kraig Brockshmidt 的书“Inside OLE”是理解 COM 的著作(甚至在 COM 之前)。这本书早于托管代码,因此这里没有托管混淆的可能性。还有第二版。

    Don Box 的书“Essential COM”和“Effective COM”较晚,但欢迎添加到(非托管)COM 知识库中。

    但是,如果您的钱包不适合购买这些尘土飞扬的旧书,Microsoft COM 教程材料here 可以帮助您走上正轨。

    黑客愉快。

    【讨论】:

    • 好吧。谢谢 :)。我可以说:“我不读书!”但这不会是一个好的职业发展,不是吗;)
    【解决方案2】:

    实例化 COM 对象的最低要求如下:

    1) 必须有可用的 COM 公寓。

    大多数应用程序通过调用 CoInitialize / CoInitializeEx 来设置 COM 库和初始 COM 单元(如果这是一个进程的第一次)来完成。

    2) 调用 CoCreateInstance / CoCreateInstanceEx 来创建一个对象,并指定标志来表示它将如何被实例化。

    3) 在您创建的任何 COM 组件的接口上适当平衡对 AddRef 和 Release 的调用,在使用完 COM 组件后调用最后一个 Release()。

    -

    在托管应用程序中,#1 几乎总是为您处理。如果您导入对 COM 库的引用,#2 将被抽象出来,您可以只使用导入的名称,就好像它们是 .NET 类定义等一样。 #3 会自动为您处理,但您的需求可能会有所不同。不幸的是,在托管应用程序中处理引用的方式有时会出现怪癖,这可能会导致 COM 对象的停留时间比预期的要长。 System.Runtime 中的 Marshal 帮助器类具有可以在遇到问题时为您提供帮助的方法。

    -

    在非托管应用程序中,如果您从头开始创建应用程序,则必须做一些跑腿工作。

    1. 在应用程序的主线程中尽早调用 CoInitialize/CoInitializeEx 以设置公寓。
    2. 当您的应用程序的主线程即将退出时,调用 CoUninitialize() 以关闭公寓。
    3. 对于您创建的其他线程,如果您需要使用这些线程中的 COM 对象,您还应该在它们启动时调用 CoInitialize/CoInitializeEx。此外,根据您的应用,您可能需要设置公寓参数。
    4. 对于这些线程,在它们退出时也调用 CoUninitialize() 以正确清理。

    【讨论】:

      【解决方案3】:

      如果你能提供更多关于你正在做什么的信息会有所帮助。你知道对象实现了哪些接口等吗?

      不过,一般而言,您可以通过 Google 获取更具体帮助的 API 是 CoCreateInstance。您需要将要玩的对象的 GUID 传递给它。所有 COM 对象都实现了 IUnknown 接口,您可以查询它可能具有的任何其他对象。因此,一些帮助您入门的示例伪代码可能类似于:

      CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
      CoCreateInstance( CLSID,
                             ptrIUnknown,
                             ClassCxt, // generally CLSCTX_INPROC_SERVER,
                             riid , // reference id
                             (void **)&pRequest); // the interface that corresponds to the riid
      

      在这里,您可以使用从 ptrIUnknown 获得的 IUnknown 接口查询其他接口。

      然后清理

      CoUninitialize()
      

      Don Box 的 Essential COM 是一本关于这个主题的好书。此外,只是为了测试您的 COM 对象如何工作,使用 VBScript 之类的东西可以让这变得超级简单。此外,可能值得注意的是,类 ID 的 GUID 以某种不寻常的方式存储,因此如果您只是从注册表中提取 GUID,则可能难以确定顺序。不过,这可能是针对不同的问题。

      【讨论】:

        【解决方案4】:

        我对 COM 对象和组件使用 ATL 智能 COM 指针和 ATL::CAxWindow 类的组合。我发现智能指针特别好用。

        http://www.murrayc.com/learning/windows/usecomfromatl.shtml

        http://76.105.92.243/notes/atlcom.html#import

        http://msdn.microsoft.com/en-us/library/yx242b61%28VS.80%29.aspx

        【讨论】:

        • 感谢您的链接,2 号看起来很有希望。直到明天才能解析所有这些:|
        • 我很想知道为什么有人投了反对票!我只是想帮忙。
        • 嗯,你成功了。谢谢。
        【解决方案5】:

        尝试使用 Visual C++ 中的#import。这将为接口创建智能指针包装器。

        【讨论】:

          【解决方案6】:

          我的博客文章中的完整示例(正是您需要的):How to Call COM Object from Visual Studio C++?

          // https://helloacm.com/how-to-call-com-object-from-visual-studio-c/
          #include <iostream>
          #include <objbase.h>
          #include <unknwn.h>
          #include <Propvarutil.h>
          #import "wshom.ocx" no_namespace, raw_interfaces_only  
          
          using namespace std;
          
          int main() {
              HRESULT hr;
              CLSID clsid;
              CoInitializeEx(nullptr, COINIT_MULTITHREADED);  
              CLSIDFromProgID(OLESTR("WScript.Shell"), &clsid);   
              IWshShell *pApp = nullptr;
              hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IWshShell), reinterpret_cast<LPVOID *>(&pApp));
              if (FAILED(hr) || pApp == nullptr) {
                  throw "Cannot Create COM Object";
              }
              int out;
              VARIANT s;
              InitVariantFromInt32(0, &s);
              VARIANT title;
              InitVariantFromString(PCWSTR(L"title"), &title);
              VARIANT type;
              InitVariantFromInt32(4096, &type);
              BSTR msg = ::SysAllocString(L"Hello from https://helloacm.com");
              pApp->Popup(msg, &s, &title, &type, &out);
              CoUninitialize();
              cout << "Out = " << out;
              return 0;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-08-06
            • 1970-01-01
            • 2010-11-19
            • 2010-10-31
            • 2018-03-17
            • 1970-01-01
            相关资源
            最近更新 更多