2009-07-17 41 views
6

我正尝试构建一个应用程序,该应用程序在本机C++中使用VisualStudio'05 中的COM组件。 MSDN中原生和管理的desciptions组合完全破坏了我的大脑。 (我认为MSDN在这方面是一团糟) 我需要一个简短的本地C++示例代码来加载我的组件 并使其可用。 我确定编译器创建包装等。如何在本地Visual C++中轻松使用COM组件

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

这可能是一个问题原生com与托管com?

我完全失去了,请给我一些轴承...

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

CLARIFICATION:我只有OCX和组件的文档 的一个线索,它应该公开什么方法。

回答

3

工作的完整示例(您需要的东西)从我的博客文章: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; 
} 
3

我很赞赏你的努力去与本地C++来处理COM - 你需要经过痛苦真正体会到今天的豪华(管理)开发环境:)

回到世界时(我)是年轻的Kraig Brockshmidt的书“Inside OLE”是 tome意义上的COM(在COM甚至是COM之前)。这本书早于托管代码,因此在这里没有管理混淆的机会。还有第二版。

Don Box的书籍“Essential COM”和“Effective COM”之后,但欢迎增加(非托管)COM知识库。

但是,如果您的钱包没有扩展到获取这些尘土飞扬的旧书,Microsoft COM教程资料here可能会帮助您设置正确的轨道。

快乐的黑客攻击。是

+0

嘛。谢谢 :)。我可以说:“我不读!”但这不会是一个很好的职业生涯,是否会;) – AndreasT 2009-07-17 22:30:31

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()。
1

如果你提供了一些关于你到底在做什么的信息,这将有所帮助。你知道对象实现什么接口吗?

一般来说,您可以通过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的基本COM清理是一个伟大的书就这个话题。另外,为了测试你的COM对象的工作方式,使用类似VBScript的东西使得这非常容易。此外,可能值得注意的是,类ID的GUID存储方式有点不同寻常,所以如果您只是从注册表中获取GUID,则可能会在确定排序时遇到一些问题。这可能是一个不同的问题。

+1

基本COM:+1 – 2009-07-17 22:02:38

1

我使用ATL智能COM指针和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

+0

感谢您的链接,2号看起来很有前途。直到明天才会解析所有这些:| – AndreasT 2009-07-17 22:22:10

+0

我很想知道为什么有人投这个票!我只是在帮助。 – Rob 2009-07-21 11:24:54

+0

那么你成功了。谢谢。 – AndreasT 2009-07-30 19:47:20

0

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