DCOM简单示例(04)

本篇文章介绍了如何写一个简单的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;
}

Comments are closed.