1. 程式人生 > >總結一下在VC中呼叫COM元件的方法+++VC呼叫遠端COM+元件

總結一下在VC中呼叫COM元件的方法+++VC呼叫遠端COM+元件

總結一下在VC中呼叫COM元件的方法

準備及條件:

COM伺服器為程序內伺服器,DLL名為simpCOM.dll,該元件只有一個介面IFoo,該介面只有一個方法HRESULT SayHello(void)


在SDK中呼叫

=====================================

一、最簡單最常用的一種,用#import匯入型別庫,利用VC提供的智慧指標包裝類

演示程式碼:


#import "D:\Temp\vc\simpCOM\Debug\simpCOM.dll" no_namespace

CoInitialize(NULL);


IFooPtr spFoo = NULL;

spFoo.CreateInstance(__uuidof(Foo));

spFoo->SayHello();

spFoo.Release();/*暈死了,本來智慧指標就是為了讓使用者不用關心這個的,可是我發現如果不手工呼叫一下的話,程式退出後會發生記憶體訪問錯誤,我是在console中做試驗的,哪位大俠知道怎麼回事請一定指教*/

CoUninitialize();

二、引入midl.exe產生的*.h,*_i.c檔案,利用CoCreateInstance函式來呼叫

演示程式碼:

/*在工程中加入*_i.c檔案,例如本例的simpCOM_i.c,該檔案定義了類和介面的guid值,如果不引入的話,會發生連線錯誤。*/

#include "D:\Temp\vc\simpCOM\simpCOM.h"

CoInitialize(NULL);

IFoo* pFoo = NULL;

HRESULT hr = CoCreateInstance(CLSID_Foo, NULL, CLSCTX_ALL, IID_IFoo, (void**)&pFoo);

if (SUCCEEDED(hr) && (pFoo != NULL))

{

       pFoo->SayHello();

       pFoo->Release();

}

CoUninitialize();

三、不用CoCreateInstance,直接用CoGetClassObejct得到類廠物件介面,然後用該介面的方法CreateInstance來生成例項。

演示程式碼:

/*前期準備如二方法所述*/

IClassFactory* pcf = NULL;

HRESULT      hr = CoGetClassObject(CLSID_Foo, CLSCTX_ALL, NULL, IID_IClassFactory, (void**)&pcf);

if (SUCCEEDED(hr) && (pcf != NULL))

{

       IFoo* pFoo = NULL;

       hr = pcf->CreateInstance(NULL, IID_IFoo, (void**)&pFoo);

       if (SUCCEEDED(hr) && (pFoo != NULL))

       {

              pFoo->SayHello();

              pFoo->Release();

       }

       pcf->Release();

}

四、不用CoCreateInstance or CoGetClassObject,直接從dll中得到DllGetClassObject,接著生成類物件及類例項(本方法適合於你想用某個元件,卻不想在登錄檔中註冊該元件)


演示程式碼:

/*前期準備工作如二方法所述,事實上只要得到CLSID和IID的定義及介面的定義就行*/

typedef HRESULT (__stdcall * pfnGCO) (REFCLSID, REFIID, void**);

pfnGCO fnGCO = NULL;

HINSTANCE hdllInst = LoadLibrary("D:\\Temp\\vc\\simpCOM\\Debug\\simpCOM.dll");

fnGCO = (pfnGCO)GetProcAddress(hdllInst, "DllGetClassObject");

if (fnGCO != 0)

{

       IClassFactory* pcf = NULL;

       HRESULT hr=(fnGCO)(CLSID_Foo, IID_IClassFactory, (void**)&pcf);

       if (SUCCEEDED(hr) && (pcf != NULL))

       {

              IFoo* pFoo = NULL;

              hr = pcf->CreateInstance(NULL, IID_IFoo, (void**)&pFoo);

              if (SUCCEEDED(hr) && (pFoo != NULL))

              {

                     pFoo->SayHello();

                     pFoo->Release();

              }

              pcf->Release();

       }

}    

FreeLibrary(hdllInst);


在MFC中呼叫

=====================================

在MFC中除了上面的幾種方法外,還有一種更方便的方法,就是通過ClassWizard利用型別庫生成包裝類,不過有個前提就是com元件的介面必須是派生自IDispatch


具體方法:

1、按Ctrl+W調出類嚮導,按Add Class按鈕彈出新選單,選From a type libarary,然後定位到simpCOM.dll,接下來會出來該simpCOM中的所有介面,選擇你想生成的介面包裝類後,嚮導會自動生成相應的.cpp和.h檔案.

這樣你就可以在你的MFC工程中像使用普通類那樣使用COM元件了.

演示程式碼:


       CoInitialize(NULL);

       IFoo foo;

       if (foo.CreateDispatch("simpCOM.Foo") != 0)

       {

              foo.SayHello();

              foo.ReleaseDispatch();

       }

       CoUninitialize();


―――――――――――――――――――――――――――――――――――――――

不好意思,不小心發出去了。


_foo,我覺得不一定要呼叫Release,估計原因是因為spFoo智慧指標物件在CoUninitialize()函式以後呼叫引起的。要是如下面這樣呼叫,應該就沒有問題了。

#import "D:\Temp\vc\simpCOM\Debug\simpCOM.dll" no_namespace

CoInitialize(NULL);

{

   IFooPtr spFoo = NULL;

   spFoo.CreateInstance(__uuidof(Foo));

   spFoo->SayHello();

}

CoUninitialize();

VC呼叫遠端COM+元件


用VB6嚮導做成COM+,並在伺服器上安裝,部分程式碼如下:(名稱為ADOMTS) 
Public Function GetADORecordset() As ADOR.Recordset 
Dim rsset As ADODB.Recordset 
Dim cn As ADODB.Connection 
Dim connectstring As String 
Dim anerror As ADODB.Error 
Dim Sql As String 
On Error GoTo rt 
connectstring = "Driver={SQL SERVER};Server=192.168.1.123;Database=pubs;UID=sa;" 
Sql = "SELECT * FROM authors;" 
Set cn = New ADODB.Connection 
cn.ConnectionString = connectstring 
cn.CursorLocation = adUseClient 
cn.Open 
Set rsset = cn.Execute(Sql) 
Set GetADORecordset = rsset 
Exit Function 
rt: 
For Each anerror In cn.Errors 
Debug.Print anerror.Number & ": " & anerror.Description & " - " & anerror.SQLState 
Next anerror 
End Function 

然後用VC6封裝DLL(工程名為connect),遠端呼叫COM+元件(將伺服器上的元件匯出並在客戶端上安裝)。利用VC MFC 

CLASSWIZARD新增新類,import from type library,將ADOMTS.tlb新增進去。部分程式碼如下: 
int _stdcall GETUSPW() 


_clsAdoRec * pAccount; 
IUnknown *pUnknown; 
HRESULT hr; 
CoInitialize(NULL);//初始化COM環境 
hr = CoInitializeSecurity( 
NULL, //Points to security descriptor 
-1, //Count of entries in asAuthSvc 
NULL, //Array of names to register 
NULL, //Reserved for future use 
RPC_C_AUTHN_LEVEL_DEFAULT, //The default authentication level for proxies 
RPC_C_IMP_LEVEL_IDENTIFY, //The default impersonation level for proxies 
NULL, //Reserved; must be set to NULL 
0, //Additional client or server-side capabilities 
NULL //Reserved for future use 
); 

COAUTHINFO sAuthInfo; 
sAuthInfo.dwAuthnSvc = RPC_C_AUTHN_DEFAULT; 
sAuthInfo.dwAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT; 
//sAuthInfo.dwAuthzSvc = RPC_C_AUTHZ_DEFAULT; 
sAuthInfo.dwAuthzSvc = RPC_C_AUTHZ_NONE; 
// sAuthInfo.dwCapabilities = EOAC_NONE;//must be 
sAuthInfo.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;//must be 
sAuthInfo.pwszServerPrincName = NULL; 
sAuthInfo.pAuthIdentityData = (COAUTHIDENTITY*)malloc(sizeof(COAUTHIDENTITY)); 
sAuthInfo.pAuthIdentityData->User = L"test" ;//訪問遠端物件所在主機的使用者名稱,寬字串 
sAuthInfo.pAuthIdentityData->UserLength =4; //使用者名稱的字元長度 
sAuthInfo.pAuthIdentityData->Password = L"test" ;//密碼,寬字串 
sAuthInfo.pAuthIdentityData->PasswordLength = 4; //密碼長度 
sAuthInfo.pAuthIdentityData->Domain = NULL; //遠端主機的域,如果沒有域則設定為NULL 
sAuthInfo.pAuthIdentityData->DomainLength = 0;//域名長度 
sAuthInfo.pAuthIdentityData->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; 
COSERVERINFO serverInfo; 
memset(&serverInfo, 0, sizeof(COSERVERINFO)); 
serverInfo.pwszName = L"192.168.1.10"; //遠端主機的名稱 
serverInfo.pAuthInfo = &sAuthInfo; 
MULTI_QI qi; 
memset(&qi, 0, sizeof(MULTI_QI)); 
qi.pIID = &IID_IUnknown; 

CLSID CLSID_InsideCOM = {0xAB363305,0x981B,0x11D1,{0x92,0x92,0x00,0xAA,0x00,0x51,0x0E,0x3B}}; 
const IID IID_IAccount={0xB363304,0x981B,0x11D1,{0x92,0x92,0x00,0xAA,0x00,0x51,0x0E,0x3B}}; 

hr=CoCreateInstanceEx(CLSID_InsideCOM,NULL,CLSCTX_REMOTE_SERVER,&serverInfo,1,&qi); 
pUnknown = (IUnknown *) qi.pItf; 
hr = pUnknown->QueryInterface(IID_IAccount,(void**)&pAccount); 
pAccount->GetADORecordset(); 
pUnknown->Release(); 


return 0; 



呼叫該DLL,單步除錯的時候,程式走到CoCreateInstanceEx函式時候沒有問題,接著執行介面查詢操作 

QueryInterface,hr返回0x80070005,訪問被拒絕。實在弄不明白,都已經CoCreateInstanceEx成功了,為什麼 QueryInterface不成功呢?是我程式碼寫的有問題嗎?

http://hi.baidu.com/mingyueye/item/53ebecd44da76917d80e4449

相關推薦

[轉]總結一下CSS的定位 Position 屬性

pub pos solid 修改 static blog style 分享 正常的 在CSS中,Position 屬性經常會用到,主要是絕對定位和相對定位,簡單的使用都沒有問題,尤其嵌套起來,就會有些混亂,今記錄總結一下,防止久而忘之。 CSS positi

如何解決spring同一個類裡面方法之間呼叫的時候註解失效的問題

參考部落格:https://blog.csdn.net/z55887/article/details/81073450 @RestController public class Test { @Autowired ApplicationContext context;

簡單總結一下Java的集合

今天面試了深圳遞四方,奇蹟般的過了,在此紀念一下哈哈 技術面有不少問題沒答好,其中一個就是集合,用了這麼久的集合,腦袋裡面還是沒有一個系統的概念,當然要痛定思痛啦! 上一個集合框架圖 然後這個看起來有點混亂,先來一個簡化的 這個圖大概要能回答的出來,常用的還要

java如何獲得一個方法呼叫深度?

函式:   Thread.currentThread().getStackTrace(); 作用:獲得在同一個執行緒,方法呼叫的深度。 案例: public class DemoTest {

總結一下面試遇到的問題,一共面試了4家公司。

基本情況:本科畢業一年,面試職位:北京的Android開發職位。         1.搜狗:             (1)5種基本的Layout:relative,linear,frame,absolute,table.               (2) wait和s

總結一下Android主題(Theme)的正確玩法

在AndroidManifest.xml檔案中有<application android:theme="@style/AppTheme">,其中的@style/AppTheme是引用的res/values/styles.xml 中的主題樣式,也有可能是引用的 res/values-v11/sty

總結一下linux的分段機制

  這篇文章主要說一下linux對於分段機制的處理,雖然都說linux不使用分段機制,但是分段機制屬於CPU的一個功能,即使linux不使用,也要通過程式碼想辦法繞過它,況且linux也使用到了分段機制中的某些功能。   分段機制主要功能只有兩點: 將實體記憶體劃分為多個段,讓作業系統可以使用

【搬運】總結一下面試被問到的jdk幾個版本之間的區別問題

1.5 1.自動裝箱與拆箱: 2.列舉(常用來設計單例模式) 3.靜態匯入 4.可變引數 5.內省 1.6 1.Web服務元資料 2.指令碼語言支援 3.JTable的排序和過濾 4.更簡單,更強大的JAX-WS 5.輕量級Http Server 6.嵌入式資料庫 Derby

VC++擷取字串的方法

在VC++程式設計中,我們有時會遇到關於擷取字串的問題,對於CString型別字串的擷取VC++中有現成的函式可供使用,主要是:CStringMid (int nFirst, int nCount);和BOOL AfxExtractSubString (CString&a

java中子類繼承父類呼叫利用繼承方法呼叫this

package cn.itcast.test1; class Parent{     public Object getObject(){         return this;     } } c

子類繼承父類,重寫父類方法,運用多型時呼叫重寫的方法呼叫子類的還是呼叫父類的?

package 第五天; public class Person { public void say() { System.out.println("我是Person的say方法"); } } 子類Student如下: package 第五天; publ

總結一下VC呼叫COM元件方法+++VC呼叫遠端COM+元件

總結一下在VC中呼叫COM元件的方法 準備及條件: COM伺服器為程序內伺服器,DLL名為simpCOM.dll,該元件只有一個介面IFoo,該介面只有一個方法HRESULT SayHello(void) 在SDK中呼叫 ====================

vc呼叫Com元件方法詳解

需求: 1.建立myCom.dll,該COM只有一個元件,兩個介面:    IGetRes--方法Hello(),    IGetResEx--方法HelloEx() 2.在工程中匯入元件或型別庫  #import "元件所在目錄myCom.dll" no_namespa

(用iis呼叫com來操縱Excel) 檢索 COM 類工廠 CLSID 為{00024500-0000-0000-C000-000000000046} 的元件時失敗,原因是出現以下錯誤: 80070005。8000401A的錯誤解決方法

.NET匯出Excel遇到的80070005錯誤的解決方法: 檢索 COM 類工廠中 CLSID 為 {00024500-0000-0000-C000-000000000046}的元件時失敗,原因是出現以下錯誤: 80070005基本上.net匯出excel檔案,都需要如此配置一下,不配置有的時候沒錯,而

VC++list::list的使用方法總結

本文主題        這幾天在做影象處理方面的研究,其中有一部分是關於影象分割方面的,影象目標在分割出來之後要做進一步的處理,因此有必要將目標影象的資訊儲存在一個變數裡面,一開始想到的是陣列,但是馬上就發現使用陣列的缺點:陣列長度固定

C++呼叫系統應用程式的方法的整理總結

一、三個SDK函式:  WinExec,ShellExecute ,CreateProcess可以實現呼叫其他程式的要求,其中以WinExec最為簡單,ShellExecute比WinExec靈活一些,CreateProcess最為複雜。WinExec 兩個引數,前一個指定路徑,後一個指

C++呼叫com控制元件方法

  最近要求做一個C++呼叫com元件的DEMO。由於自己對C++並無研究包括IDE工具。後來在網上查閱了些資料,經過努力終於告一段落。    網上對於C++載入com元件的方法已經說的很多了,我就僅貼下我所使用的方法(不用註冊dll,當然網上推薦了一些更簡單也更有

vue元件間迴圈呼叫,子元件呼叫最父層方法 的 解決方案

問題描述:最近的VUE專案中遇到樹形結構的選單。複用樹形的選單的元件。但需要呼叫元件最父層的方法。一般父子間元件用 this.$emit 傳遞,或者只有一層的情況下用 this.$parent.xxx可參考:https://cn.vuejs.org/v2/guide/comp

COM元件註冊方法(VC++)

1、開啟VC的屬性介面進行設定 2、註冊DLL到系統 CString szInfo, szPath; char cPath[MAX_PATH] = {0}; GetModuleFileNam

7zip壓縮與解壓縮在vc++呼叫方法例子

 最近在做關於壓縮與解壓縮的程式,在網上找了很長時間,很多的文章都很難理解,經過大半天的嘗試終於找到一種解決辦法,現在以其中的一種壓縮和解壓縮的方式的例子給大家呈現: 首先要有7zip的可執行檔案7z.exe,假設已經將該可執行檔案放自己的專案目錄下,即和自己的可執行檔案放