本篇文章介绍了如何写一个简单的DCOM客户端(CPP)。
首先是本地调用:
代码中展示了三种获取CLSID的方式,任选一种就好了。
#include "stdafx.h"
#include "windows.h"
#include <iostream>
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
MIDL_DEFINE_GUID(CLSID, CLSID_JustATestExe,0xD49F1BFF,0x60FB,0x4A43,0xA9,0xAA,0x49,0x93,0xD5,0x55,0x95,0x74);
int _tmain(int argc, _TCHAR* argv[])
{
// COM 初始化
::CoInitialize(NULL);
// 通过 ProgID 得到 CLSID
CLSID clsid;
HRESULT hr = ::CLSIDFromProgID(L"ATLExe.JustATestExe.1", &clsid);
if(!SUCCEEDED(hr))
{
std::cout << "clsid not found" << std::endl;
getchar();
return -1;
}
// 由 CLSID 启动组件,并得到 IDispatch 指针
IDispatch * pDisp = NULL;
hr = ::CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IDispatch, (LPVOID *)&pDisp);
/*
// 从ATLExe_i.c获取GUID
// 由 CLSID 启动组件,并得到 IDispatch 指针
IDispatch * pDisp = NULL;
hr = ::CoCreateInstance(CLSID_JustATestExe, NULL, CLSCTX_ALL, IID_IDispatch, (LPVOID *)&pDisp);
*/
/*
// 通过CLSIDFromString获取CLSID
LPWSTR guidstr = L("{D49F1BFF-60FB-4A43-A9AA-4993D5559574}");
GUID guid;
hr = CLSIDFromString(guidstr, (LPCLSID)&guid);
if (!SUCCEEDED(hr))
{
std::cout << "CLSIDFromString failed";
DWORD d = GetLastError();
getchar();
return -1;
}
// 由 CLSID 启动组件,并得到 IDispatch 指针
IDispatch * pDisp = NULL;
hr = ::CoCreateInstance(guid, NULL, CLSCTX_ALL, IID_IDispatch, (LPVOID *)&pDisp);
*/
if (!SUCCEEDED(hr))
{
std::cout << "IDispatch not found" << std::endl;
DWORD d = GetLastError();
getchar();
return -1;
}
LPOLESTR pwFunNameAdd = L"Add"; // 准备取得 Add 函数的序号 DispID
DISPID dispIDAdd; // 取得的序号,准备保存到这里
hr = pDisp->GetIDsOfNames( // 根据函数名,取得序号的函数
IID_NULL,
&pwFunNameAdd, // 函数名称的数组
1, // 函数名称数组中的元素个数
LOCALE_SYSTEM_DEFAULT, // 使用系统默认的语言环境
&dispIDAdd); // 返回值
if (!SUCCEEDED(hr))
{
std::cout << "Add not found" << std::endl;
getchar();
return -1;
}
VARIANTARG vAdd[2]; // 调用 Add(1,2) 函数所需要的参数
vAdd[0].vt = VT_I4; vAdd[0].lVal = 2; // 第二个参数,整数2
vAdd[1].vt = VT_I4; vAdd[1].lVal = 1; // 第一个参数,整数1
DISPPARAMS dispParamsAdd = {vAdd, NULL, 2, 0 }; // 把参数包装在这个结构中
VARIANT vResultAdd; // 函数返回的计算结果
hr = pDisp->Invoke( // 调用函数
dispIDAdd, // 函数由 dispID 指定
IID_NULL,
LOCALE_SYSTEM_DEFAULT, // 使用系统默认的语言环境
DISPATCH_METHOD, // 调用的是方法,不是属性
&dispParamsAdd, // 参数
&vResultAdd, // 返回值
NULL, // 不考虑异常处理
NULL); // 不考虑错误处理
if (!SUCCEEDED(hr))
{
std::cout << "Invoke failed" << std::endl;
getchar();
return -1;
}
std::cout << vResultAdd.lVal << std::endl;
LPOLESTR pwFunNameSayHiTo = L"SayHiTo"; // 准备取得 SayHiTo 函数的序号 DispID
DISPID dispIDSayHiTo; // 取得的序号,准备保存到这里
hr = pDisp->GetIDsOfNames( // 根据函数名,取得序号的函数
IID_NULL,
&pwFunNameSayHiTo, // 函数名称的数组
1, // 函数名称数组中的元素个数
LOCALE_SYSTEM_DEFAULT, // 使用系统默认的语言环境
&dispIDSayHiTo); // 返回值
if (!SUCCEEDED(hr))
{
std::cout << "SayHiTo not found" << std::endl;
getchar();
return -1;
}
VARIANTARG vSayHiTo[1]; // 调用 vSayHiTo("dcom") 函数所需要的参数
vSayHiTo[0].vt = VT_BSTR; vSayHiTo[0].bstrVal = L"dcom"; // 第一个参数,字符串dcom
DISPPARAMS dispParamsSayHiTo = { vSayHiTo, NULL, 1, 0 }; // 把参数包装在这个结构中
VARIANT vResultSayHiTo; // 函数返回的计算结果
hr = pDisp->Invoke( // 调用函数
dispIDSayHiTo, // 函数由 dispID 指定
IID_NULL,
LOCALE_SYSTEM_DEFAULT, // 使用系统默认的语言环境
DISPATCH_METHOD, // 调用的是方法,不是属性
&dispParamsSayHiTo, // 参数
&vResultSayHiTo, // 返回值
NULL, // 不考虑异常处理
NULL); // 不考虑错误处理
if (!SUCCEEDED(hr))
{
std::cout << "Invoke failed" << std::endl;
getchar();
return -1;
}
std::wcout << vResultSayHiTo.bstrVal<< std::endl;
pDisp->Release(); // 释放接口指针
::CoUninitialize(); // 释放 COM
getchar();
return 0;
}
然后是远程调用:
#include "stdafx.h"
#include "windows.h"
#include <iostream>
int _tmain(int argc, _TCHAR* argv[])
{
// COM 初始化
::CoInitialize(NULL);
// 通过 ProgID 得到 CLSID
CLSID clsid;
HRESULT hr = ::CLSIDFromProgID(L"ATLService.JustATestSvc", &clsid);
if(!SUCCEEDED(hr))
{
std::cout << "clsid not found" << std::endl;
getchar();
return -1;
}
// 由 CLSID 启动组件,并得到 IDispatch 指针
//IDispatch * pDisp = NULL;
//hr = ::CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IDispatch, (LPVOID *)&pDisp);
COSERVERINFO coServerInfo;
ZeroMemory(&coServerInfo, sizeof(COSERVERINFO));
coServerInfo.pwszName = TEXT("127.0.0.1");
coServerInfo.pAuthInfo = NULL;
coServerInfo.dwReserved1 = 0;
coServerInfo.dwReserved2 = 0;
MULTI_QI mqi;
ZeroMemory(&mqi, sizeof(MULTI_QI));
mqi.pIID=&IID_IDispatch;
mqi.pItf=NULL;
mqi.hr=0;
hr = CoCreateInstanceEx(clsid,
NULL,
CLSCTX_ALL,
&coServerInfo,
1,
&mqi);
IDispatch * pDisp = (IDispatch*)mqi.pItf;
if (!SUCCEEDED(hr))
{
std::cout << "IDispatch not found" << std::endl;
DWORD d = GetLastError();
getchar();
return -1;
}
LPOLESTR pwFunNameAdd = L"Add"; // 准备取得 Add 函数的序号 DispID
DISPID dispIDAdd; // 取得的序号,准备保存到这里
hr = pDisp->GetIDsOfNames( // 根据函数名,取得序号的函数
IID_NULL,
&pwFunNameAdd, // 函数名称的数组
1, // 函数名称数组中的元素个数
LOCALE_SYSTEM_DEFAULT, // 使用系统默认的语言环境
&dispIDAdd); // 返回值
if (!SUCCEEDED(hr))
{
std::cout << "Add not found" << std::endl;
getchar();
return -1;
}
VARIANTARG vAdd[2]; // 调用 Add(1,2) 函数所需要的参数
vAdd[0].vt = VT_I4; vAdd[0].lVal = 2; // 第二个参数,整数2
vAdd[1].vt = VT_I4; vAdd[1].lVal = 1; // 第一个参数,整数1
DISPPARAMS dispParamsAdd = {vAdd, NULL, 2, 0 }; // 把参数包装在这个结构中
VARIANT vResultAdd; // 函数返回的计算结果
hr = pDisp->Invoke( // 调用函数
dispIDAdd, // 函数由 dispID 指定
IID_NULL,
LOCALE_SYSTEM_DEFAULT, // 使用系统默认的语言环境
DISPATCH_METHOD, // 调用的是方法,不是属性
&dispParamsAdd, // 参数
&vResultAdd, // 返回值
NULL, // 不考虑异常处理
NULL); // 不考虑错误处理
if (!SUCCEEDED(hr))
{
std::cout << "Invoke failed" << std::endl;
getchar();
return -1;
}
std::cout << vResultAdd.lVal << std::endl;
LPOLESTR pwFunNameSayHiTo = L"SayHiTo"; // 准备取得 SayHiTo 函数的序号 DispID
DISPID dispIDSayHiTo; // 取得的序号,准备保存到这里
hr = pDisp->GetIDsOfNames( // 根据函数名,取得序号的函数
IID_NULL,
&pwFunNameSayHiTo, // 函数名称的数组
1, // 函数名称数组中的元素个数
LOCALE_SYSTEM_DEFAULT, // 使用系统默认的语言环境
&dispIDSayHiTo); // 返回值
if (!SUCCEEDED(hr))
{
std::cout << "SayHiTo not found" << std::endl;
getchar();
return -1;
}
VARIANTARG vSayHiTo[1]; // 调用 vSayHiTo("dcom") 函数所需要的参数
vSayHiTo[0].vt = VT_BSTR; vSayHiTo[0].bstrVal = TEXT("dcom"); // 第一个参数,字符串dcom
DISPPARAMS dispParamsSayHiTo = { vSayHiTo, NULL, 1, 0 }; // 把参数包装在这个结构中
VARIANT vResultSayHiTo; // 函数返回的计算结果
hr = pDisp->Invoke( // 调用函数
dispIDSayHiTo, // 函数由 dispID 指定
IID_NULL,
LOCALE_SYSTEM_DEFAULT, // 使用系统默认的语言环境
DISPATCH_METHOD, // 调用的是方法,不是属性
&dispParamsSayHiTo, // 参数
&vResultSayHiTo, // 返回值
NULL, // 不考虑异常处理
NULL); // 不考虑错误处理
if (!SUCCEEDED(hr))
{
std::cout << "Invoke failed" << std::endl;
getchar();
return -1;
}
std::wcout << vResultSayHiTo.bstrVal<< std::endl;
pDisp->Release(); // 释放接口指针
::CoUninitialize(); // 释放 COM
getchar();
return 0;
}