COM初探(四)——本地EXE COM服务器

COM初探(四)——本地EXE COM服务器

(一)目标
讲述如何建立本地(Local,EXE)COM服务器的例子似乎不多,为此,本文专门讲述如何用vc手工建立本地EXE COM服务器程序。本文假设读者对COM有一定的基础。

(二)准备
 1)使用vc6建立Win32 Application工程,选择a simple application。
 2)从stdafx.h中删除:#define WIN32_LEAN_AND_MEAN

(三)建立IDL文件
此文件中定义了接口ITimeBeijing和COM类TimeBeijingClass

import "oaidl.idl";

[
 object,
 uuid(61A1C81D-82CA-44e4-A60E-7BDD8E58A833),
 oleautomation
]
interface ITimeBeijing : IUnknown//定义ITimeBeijing接口
{
 HRESULT GetTimeBeijing([out]int * hour, [out]int * min, [out]int * sec);
};

[
 uuid(1E850106-D5C5-4249-86DF-40256DB3A5D2),
 version(1.0)
]
library TimeBeijingLib
{
   importlib("stdole32.tlb");
   [
  uuid(57E9BE40-AE4F-493b-A79B-FBBF7EC7F2AE)
   ]
   coclass TimeBeijingClass//定义TimeBeijingClass类
   {
      [default] interface ITimeBeijing;
   };
};

(四)添加COM类TimeBeijingClass
TimeBeijingClass在由上面idl文件编译生成的文件中已经前置声明了。这里我们实现了它的功能(获取当前北京时间)

// TimeBeijingClass.h: interface for the TimeBeijingClass class.
//
//

#if !defined(AFX_TIMEBEIJINGCLASS_H__E9D2F0AF_8EBB_438B_A2BC_6206DDAB91B6__INCLUDED_)
#define AFX_TIMEBEIJINGCLASS_H__E9D2F0AF_8EBB_438B_A2BC_6206DDAB91B6__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "TimeBeijing.h"

class TimeBeijingClass : public ITimeBeijing 
{
public:
 TimeBeijingClass();
 ~TimeBeijingClass();

private:
 ULONG m_cRef;

public:
 //IUnknown 方法
 STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
 STDMETHOD_(ULONG, AddRef)();
 STDMETHOD_(ULONG, Release)();

 //ITimeBeijing 方法
 STDMETHOD(GetTimeBeijing)(int * hour, int* min, int * sec);

};

#endif // !defined(AFX_TIMEBEIJINGCLASS_H__E9D2F0AF_8EBB_438B_A2BC_6206DDAB91B6__INCLUDED_)


// TimeBeijingClass.cpp: implementation of the TimeBeijingClass class.
//
//
#include "StdAfx.h"
#include "TimeBeijingClass.h"
#include "time.h"
#include "stdio.h"
#include "TimeBeijing_i.c"
//
// Construction/Destruction
//

TimeBeijingClass::TimeBeijingClass()
{
 printf("TimeBeijingClass - constructor/n");
 m_cRef = 0;
}

TimeBeijingClass::~TimeBeijingClass()
{
 printf("TimeBeijingClass - destructor/n");
}

STDMETHODIMP TimeBeijingClass::QueryInterface(REFIID riid, void **ppv)
{
 printf("TimeBeijingClass - QueryInterface/n");
 if(riid == IID_ITimeBeijing)
  *ppv = static_cast<ITimeBeijing *>(this);
 else if(riid == IID_IUnknown)
  *ppv = static_cast<ITimeBeijing *>(this);
 else {
  *ppv = 0;
  return E_NOINTERFACE;
 }
 
 reinterpret_cast<IUnknown *>(*ppv)->AddRef();
 return S_OK;
}

STDMETHODIMP_(ULONG) TimeBeijingClass::AddRef()
{
 printf("TimeBeijingClass - AddRef/n");
 return ++m_cRef;
}

STDMETHODIMP_(ULONG) TimeBeijingClass::Release()
{
 printf("TimeBeijingClass - Release/n");
 ULONG res = --m_cRef; 
 if(res == 0)
  delete this;
 return res;
}

STDMETHODIMP TimeBeijingClass::GetTimeBeijing(int * hour, int* min, int * sec)
{
 printf("TimeBeijingClass - GetTimeBeijing/n");
 
 time_t ltime;
 struct tm *today;
 
 time(&ltime);
 today = localtime(&ltime);
 
 *hour = today->tm_hour;
 *min = today->tm_min;
 *sec = today->tm_sec;
 
 return S_OK;
}

(五)添加工厂类TimeBeijingClassFactory
类工厂可以生成类的实例。在标准的COM实现中,我们都是通过使用类工厂来得到目的接口指针的。
类工厂从IClassFactory接口派生,有两个接口函数:CreateInstance和LockServer。
CreateInstance用于建立目标COM类的实例并返回相应接口。
LockServer用于全局的引用计数。当计数为0时,服务器自动关闭。

// TimeBeijingClassFactory.h: interface for the TimeBeijingClassFactory class.
//
//

#if !defined(AFX_TIMEBEIJINGCLASSFACTORY_H__AB2637DD_45D2_48CD_BAD8_46E372268A8C__INCLUDED_)
#define AFX_TIMEBEIJINGCLASSFACTORY_H__AB2637DD_45D2_48CD_BAD8_46E372268A8C__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <unknwn.h>

class TimeBeijingClassFactory : public IClassFactory 
{
public:
 TimeBeijingClassFactory();
 ~TimeBeijingClassFactory();

public:
 //IUnknow 方法
 STDMETHODIMP QueryInterface(REFIID,void**);
 STDMETHODIMP_(ULONG) AddRef();
 STDMETHODIMP_(ULONG) Release();
 
 //IClassFactory 方法
 STDMETHODIMP CreateInstance(IUnknown * ,REFIID ,void **);
 STDMETHODIMP LockServer(BOOL fLock);
 
private:
 LONG m_cRef;

};

#endif // !defined(AFX_TIMEBEIJINGCLASSFACTORY_H__AB2637DD_45D2_48CD_BAD8_46E372268A8C__INCLUDED_)


// TimeBeijingClassFactory.cpp: implementation of the TimeBeijingClassFactory class.
//
//
#include "StdAfx.h"
#include "TimeBeijingClassFactory.h"
#include "stdio.h"
#include "TimeBeijingClass.h"
//
// Construction/Destruction
//

extern LONG g_cObjectAndLocks;

TimeBeijingClassFactory::TimeBeijingClassFactory()
{
 printf("TimeBeijingClassFactory - constructor/n");
 m_cRef = 0;
}

TimeBeijingClassFactory::~TimeBeijingClassFactory()
{
 printf("TimeBeijingClassFactory - destructor/n");
}

STDMETHODIMP_(ULONG) TimeBeijingClassFactory::AddRef(void)
{
 printf("TimeBeijingClassFactory - AddRef/n");
 return InterlockedIncrement(&m_cRef);
}

STDMETHODIMP_(ULONG) TimeBeijingClassFactory::Release(void)
{
 printf("TimeBeijingClassFactory - Release/n");
 return ::InterlockedDecrement(&m_cRef);
}

STDMETHODIMP TimeBeijingClassFactory::QueryInterface(REFIID riid,void ** ppv)
{
 printf("TimeBeijingClassFactory - QueryInterface/n");

 *ppv = NULL;
 if(riid == IID_IUnknown || riid == IID_IClassFactory)
 {
  *ppv = static_cast<IClassFactory *>(this);
  reinterpret_cast<IUnknown*>(*ppv)->AddRef();
  return S_OK;
 }
 else
  return (*ppv=0),E_NOINTERFACE;
}

STDMETHODIMP TimeBeijingClassFactory::CreateInstance(IUnknown * pUnkOuter,REFIID riid,void ** ppv)
{
 printf("TimeBeijingClassFactory - CreateInstance/n");

 *ppv=NULL;
 
 if(pUnkOuter != NULL)
  return CLASS_E_NOAGGREGATION;
 
 TimeBeijingClass * pTimeBeijingClass = new TimeBeijingClass;
 if(pTimeBeijingClass == NULL)
  return E_OUTOFMEMORY;
 
 HRESULT hr = pTimeBeijingClass->QueryInterface(riid,ppv);
 
 if(FAILED(hr))
  delete pTimeBeijingClass;
 
 return hr;
 
}

STDMETHODIMP TimeBeijingClassFactory::LockServer(BOOL fLock)
{
 printf("TimeBeijingClassFactory - LockServer/n");
 if(fLock)
  ::InterlockedIncrement(&g_cObjectAndLocks);
 else
 {
  if(0 == ::InterlockedDecrement(&g_cObjectAndLocks))
   PostQuitMessage(0);
 }
 return NOERROR;
 
}

(六)服务器端主文件
客户端主文件负责注册工厂类,使得外部程序可以访问本地的COM类。

#include "stdafx.h"
#include "TimeBeijing_i.c"
#include "TimeBeijingClassFactory.h"

LONG g_cObjectAndLocks;//用于全局的应用计数

int APIENTRY WinMain(HINSTANCE hInstance,//程序的入口点
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
 HRESULT hr;

 CoInitialize(NULL);  //初始化COM环境
 
 //读入并注册类型库
 ITypeLib* pTLib = NULL;
 hr = LoadTypeLibEx(L"TimeBeijing.tlb", REGKIND_REGISTER, &pTLib);
 pTLib->Release();

 if ( FAILED(hr) )
 {
  MessageBox(NULL, "LoadTypeLibEx() failed", "", MB_OK);
  exit(1);
 }
 
 // 判断是否被SCM调用
    if(strstr(lpCmdLine, "/Embedding") || strstr(lpCmdLine, "-Embedding"))
 {
  MessageBox(NULL, "TimeBeijing Server is registering the classes",
   "EXE Message!", MB_OK | MB_SETFOREGROUND);
  
  // 工厂类
  TimeBeijingClassFactory ClassFactory;
  
  // 注册工厂类
  DWORD regID = 0;
  hr = CoRegisterClassObject(CLSID_TimeBeijingClass,
   (IClassFactory*)&ClassFactory,
   CLSCTX_LOCAL_SERVER,
   REGCLS_MULTIPLEUSE,
   &regID);

  if ( FAILED(hr) )
  {
   MessageBox(NULL, "CoRegisterClassObject()", "", MB_OK);
   CoUninitialize();
   exit(1);
  }
  
  // 进入消息循环,直到WM_QUIT到达
  MSG ms;
  while(GetMessage(&ms, 0, 0, 0))
  {
   TranslateMessage(&ms);
   DispatchMessage(&ms);
  }
  
  // 注销工厂类
  CoRevokeClassObject(regID); 
 }
 
 // 退出COM环境
 CoUninitialize(); 

 MessageBox(NULL, "Server is dying",
  "EXE Message!", MB_OK | MB_SETFOREGROUND);
 
 return 0;
}

(七)建立注册文件
注册文件用于添加程序注册表信息,文件内容如下:

REGEDIT
HKEY_CLASSES_ROOT/Justin.TimeBeijingServer.TimeBeijingClass/CLSID = {57E9BE40-AE4F-493b-A79B-FBBF7EC7F2AE}
HKEY_CLASSES_ROOT/CLSID/{57E9BE40-AE4F-493b-A79B-FBBF7EC7F2AE} = Justin.TimeBeijingServer.TimeBeijingClass
HKEY_CLASSES_ROOT/CLSID/{57E9BE40-AE4F-493b-A79B-FBBF7EC7F2AE}/LocalServer32 = D:/COM/Debug/COM.exe

双击此文件,将注册信息加入注册表。

(八)建立客户端
上面的程序编译链接后就可以得到一个本地EXE COM服务器。下面为了测试,我们将建立一个客户程序。

// TEST.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "TEST.h"
#include "../TimeBeijing.h"
#include "../TimeBeijing_i.c"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// The one and only application object

CWinApp theApp;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
 cout << "初始化COM环境" << endl;

 CoInitialize(NULL);

 HRESULT hr;
 IClassFactory* pICF = NULL;//定义接口指针
 
 ITimeBeijing *pTimeBeijing = NULL;
 
 cout << "获取工厂接口指针" << endl;

 hr = CoGetClassObject(CLSID_TimeBeijingClass,
  CLSCTX_LOCAL_SERVER,
  NULL,
  IID_IClassFactory,
  (void**)&pICF);

 if ( FAILED(hr) )
 {
  MessageBox(NULL, "CoGetClassObject()", "fail", MB_OK);
  exit(1);
 }
 
 cout << "获取ITimeBeijing接口指针" << endl;

 hr = pICF->CreateInstance(NULL,
  IID_ITimeBeijing,
  (void**)&pTimeBeijing);

 if ( FAILED(hr) )
 {
  MessageBox(NULL, "CoCreateInstance()", "fail", MB_OK);
  exit(1);
 }
 
 int h, m, s;
 pTimeBeijing->GetTimeBeijing(&h, &m, &s);//使用接口

 printf("Time NOW : %d : %d : %d/n", h, m, s);//显示结果
 
 if ( pICF )         pICF->Release();//释放接口
 if ( pTimeBeijing ) pTimeBeijing->Release();
 
 cout << "退出COM环境" << endl;

 CoUninitialize();

 cout << "END" << endl;

 getchar();
 return 0;
}

(九)测试结果
  初始化COM环境
  获取工厂接口指针
  获取ITimeBeijing接口指针
  Time NOW : 12 : 54 : 23
  退出COM环境
  END

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值