玩转Windows服务系列——给Windows服务添加COM接口

admin
963
文章
3
评论
2020年1月15日09:37:16 评论 38 2228字阅读7分25秒

当我们运行一个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接口

创建基于ATL的Windows服务可以参考 玩转Windows服务系列——创建Windows服务

接下来,快速给服务添加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

参考资料

Step by Step COM Tutorial

COM in C++

COM(C++) programming tutorials

C/C++ COM Code Example: Reading Messages Asynchronously

继续阅读
  • 文本由 发表于 2020年1月15日09:37:16
  • 除非特殊声明,本站文章均为原创,转载请务必保留本文链接
Git-TortoiseGit完整配置流程 技术文章

Git-TortoiseGit完整配置流程

每次使用Git的时候都或多或少遇到些问题,为了方便以后少踩一些坑,把自己踩过的坑记录一下,加深对Git使用的理解,所以写下这篇日记记录一下。 本文需要频繁使用cmd,如果使用系统的cmd会稍微有点不便...
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: