本篇文章介绍了如何写一个简单的COM+客户端(CPP)。
#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"ATLCOMP.JustATestCOMP", &clsid); HRESULT hr = ::CLSIDFromProgID(L"CSDll.JustATestCSSvc", &clsid); if(!SUCCEEDED(hr)) { std::cout << "clsid not found" << std::endl; getchar(); return -1; } // 由 CLSID 启动组件,并得到 IDispatch 指针 COAUTHIDENTITY authIdentity; authIdentity.User = (USHORT *)L"DCOMTEST"; authIdentity.UserLength = wcslen(L"DCOMTEST"); //authIdentity.Domain = (USHORT *)L"Domain"; //authIdentity.DomainLength = wcslen(L"Domain"); authIdentity.Password = (USHORT *)L"DCOMTEST"; authIdentity.PasswordLength = wcslen(L"DCOMTEST"); authIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; COAUTHINFO authInfo; ZeroMemory(&authInfo, sizeof(COAUTHINFO)); authInfo.dwAuthnSvc = RPC_C_AUTHN_NONE; authInfo.dwAuthzSvc = RPC_C_AUTHZ_NONE; //authInfo.dwAuthnSvc = RPC_C_AUTHZ_DEFAULT; //authInfo.dwAuthzSvc = RPC_C_AUTHZ_DEFAULT; //authInfo.pwszServerPrincName = L"Domain\\MachineName"; authInfo.dwAuthnLevel = RPC_C_AUTHN_LEVEL_NONE; authInfo.dwImpersonationLevel = RPC_C_IMP_LEVEL_ANONYMOUS; //authInfo.pAuthIdentityData = &authIdentity; //authInfo.dwCapabilities = EOAC_NONE; COSERVERINFO coServerInfo; ZeroMemory(&coServerInfo, sizeof(COSERVERINFO)); coServerInfo.pwszName = TEXT("172.16.172.3"); coServerInfo.pAuthInfo = NULL; coServerInfo.dwReserved1 = 0; coServerInfo.dwReserved2 = 0; coServerInfo.pAuthInfo = &authInfo; 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; }
如果是本机测试(带IP),一般不会遇到权限问题
PS:
用了一晚上时间,只能调通Win7与Win7之间远程调用,无法调通Win7与XP之间远程调用(总是各种提示Access is Denied)。
如果有谁调通过,麻烦留言告诉我一下。谢谢!