2009-07-17 240 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++#進口。這將爲接口創建智能指針包裝器。

相關問題