1. 程式人生 > >玩轉Windows服務系列——給Windows服務新增COM介面

玩轉Windows服務系列——給Windows服務新增COM介面

當我們執行一個Windows服務的時候,一般情況下,我們會選擇以非視窗或者非控制檯的方式執行,這樣,它就只是一個後臺程式,沒有介面供我們進行互動。

那麼當我們想與Windows服務進行實時互動的時候,我們應該怎麼做呢?

快速給Windows服務新增實時互動功能的方案

Windows服務是一個程序,而我們用於互動的程式,又是另外一個程序。我們與Windows服務實時互動,其實就是一個程序間通訊的問題。所有的程序間通訊的方案基本上都適用於實時互動的方案,比如Socket、共享記憶體、管道、COM等。

這些方案中,當屬COM的開發最快速,因為我們是給基於ATL的Windows服務新增COM介面嘛。

COM簡介

元件物件模型,英文為Component Object Model,縮寫COM,是微軟的一套軟體元件的二進位制介面標準。這使得跨程式語言的程序間通訊、動態物件建立成為可能。COM是多項微軟技術與框架的基礎,包括OLE, OLE自動化, ActiveX, COM+, DCOM, Windows shell, DirectX, Windows Runtime。詳細介紹可以參考 元件物件模型

給服務新增COM介面

接下來,快速給服務新增COM介面。

首先給專案添加了一個ATL簡單物件,如下:

新增類選單

ATL簡單物件

類命名

按上面步驟建立了ATL簡單物件後,會產生這麼一個檔案:

ServiceComTest.idl

檔案內容如下:

import "oaidl.idl";
import "ocidl.idl";

[
    object,
    uuid(4DDE5CA3-F5D7-4BC3-9045-E697297C5530),
    dual,
    nonextensible,
    pointer_default(unique)
]
interface IIServiceComTest : IDispatch{
};
[
    uuid(54A347BA-7689-4578-A346-C96D924BD637),
    version(
1.0), ] library ServiceComTestLib { importlib("stdole2.tlb"); [ uuid(C264868C-91E7-4BFE-8DD9-32D0804E44F6) ] coclass IServiceComTest { [default] interface IIServiceComTest; }; };

這個idl檔案就是用來定義COM介面的。

接下來給介面新增新的方法。

在類檢視中,找到剛剛生成的介面 IIServiceComTest:

類檢視

然後右鍵選單,新增方法:

新增方法

方法

IDL特性

這樣,就添加了一個add方法,x、y為輸入,result為輸出。

然後可以在idl檔案中看到add方法的定義:

interface IIServiceComTest : IDispatch{
    [id(1), helpstring("兩個整數相加")] HRESULT add([in] LONG x, [in] LONG y, [out, retval] LONG* result);
};

實現COM介面

我們給COM介面新增的方法,只是一個宣告、描述,我們還必須實現這個方法,其他程序才能與此服務通訊。

在IServiceComTest.cpp檔案中可以找到此方法:

STDMETHODIMP CIServiceComTest::add(LONG x, LONG y, LONG* result)
{
    // TODO:  在此新增實現程式碼

    return S_OK;
}

接下來就是實現此方法,如下:

STDMETHODIMP CIServiceComTest::add(LONG x, LONG y, LONG* result)
{
    *result = x + y;
    return S_OK;
}

這樣,一個完整的COM介面及其實現就算是完成了,接下來需要通過測試程式呼叫此介面進行測試了。

呼叫COM介面

建立一個基本的控制檯程式,然後將初始化測試程式碼,進行測試,程式碼如下:

#include "..\ServiceComTest\ServiceComTest_i.c"
#include "..\ServiceComTest\ServiceComTest_i.h"
#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    IIServiceComTest* test;
    CoInitialize(NULL);
    auto hresult = CoCreateInstance(CLSID_IServiceComTest,
        NULL,
        CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_HANDLER,
        IID_IIServiceComTest,
        (void**)&test);

    LONG x = 1;
    LONG y = 2;
    LONG result = 0;
    hresult = test->add(x, y, &result);
    cout << "result is " << result << endl;
    system("pause");
}

這裡,只是一個演示程式,省略了程式碼的錯誤處理。

執行程式,得到了正確的結果,result is 3, 結果如下:

result

參考資料

系列連結