COM初探(三)
(一)目标
COM初探(一)和(二)中实现的并非真正的COM程序。但是,前两步都是深入学习COM所必须经历的过程。本篇将实现一个完全的COM程序。此程序使用CoCreateInstance来获得COM对象的接口。
(二)定义接口ITimeBeijing
import "oaidl.idl";
import "ocidl.idl";
[
uuid(AA4F6A70-E521-4d46-9F4B-BC23424CEA5B),
object,
pointer_default(unique)
]
interface ITimeBeijing : IUnknown
{
HRESULT GetTimeBeijing([out]int* hour, [out]int* min, [out]int* sec);
};
[
uuid(1DC3957D-B808-4e5c-B360-1DAE5B3EBED4),
version(1.0),
]
library TimeBeijingLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(FB492283-0A76-400d-879F-5B70FBF0A493),
]
coclass TimeBeijingClass
{
[default] interface ITimeBeijing;
};
};
(三)定义和实现COM类TimeBeijingClass
// 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 Interface
STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
//ITimeBeijing Interface
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 "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(<ime);
today = localtime(<ime);
*hour = today->tm_hour;
*min = today->tm_min;
*sec = today->tm_sec;
return S_OK;
}
(四)定义和实现类工厂TimeBeijingClassFactory
// 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 Method
STDMETHODIMP QueryInterface(REFIID,void**);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
//IClassFactory Method
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 "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
::InterlockedDecrement(&g_cObjectAndLocks);
return NOERROR;
}
(五)DLL服务器主文件
#include <windows.h>
#include <objbase.h>
#include <initguid.h>
#include "TimeBeijingClassFactory.h"
#include "TimeBeijing_i.c"
LONG g_cObjectAndLocks=0;
const char * g_RegTable[][3]={
{"CLSID//{FB492283-0A76-400d-879F-5B70FBF0A493}",
0,
"TimeBeijing"},
{"CLSID//{FB492283-0A76-400d-879F-5B70FBF0A493}//InprocServer32",
0,
(const char * )-1},
{"CLSID//{FB492283-0A76-400d-879F-5B70FBF0A493}//ProgID",
0,
"Justin.TimeBeijing.2"},
{"Justin.TimeBeijing.2",
0,
"TimeBeijing"},
{"Justin.TimeBeijing.2//CLSID",
0,
"{FB492283-0A76-400d-879F-5B70FBF0A493}"},
};
HINSTANCE g_hinstDll;
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
g_hinstDll = (HINSTANCE)hModule;
return TRUE;
}
STDAPI DllUnregisterServer(void)//从注册表中注销
{
HRESULT hr = S_OK;
char szFileName [MAX_PATH];
::GetModuleFileName(g_hinstDll,szFileName,MAX_PATH);
int nEntries = sizeof(g_RegTable) / sizeof(*g_RegTable);
for(int i = 0; SUCCEEDED(hr) && i < nEntries; i ++)
{
const char * pszKeyName = g_RegTable[i][0];
long err = ::RegDeleteKey(HKEY_CLASSES_ROOT, pszKeyName);
if( err != ERROR_SUCCESS)
hr = S_FALSE;
}
return hr;
}
STDAPI DllRegisterServer(void)//注册服务器
{
HRESULT hr = S_OK;
char szFileName [MAX_PATH];
::GetModuleFileName(g_hinstDll, szFileName, MAX_PATH);
int nEntries = sizeof(g_RegTable) / sizeof(*g_RegTable);
for(int i = 0 ; SUCCEEDED(hr) && i < nEntries; i ++)
{
const char * pszKeyName = g_RegTable[i][0];
const char * pszValueName = g_RegTable[i][1];
const char * pszValue = g_RegTable[i][2];
if(pszValue == (const char *) - 1)
{
pszValue = szFileName;
}
HKEY hkey;
long err = ::RegCreateKey(HKEY_CLASSES_ROOT, pszKeyName, &hkey);
if(err == ERROR_SUCCESS)
{
err = ::RegSetValueEx( hkey,
pszValueName,
0,
REG_SZ,
( const BYTE*)pszValue,
( strlen(pszValue)+1 ) );
::RegCloseKey(hkey);
}
if( err != ERROR_SUCCESS)
{
::DllUnregisterServer();
hr = E_FAIL;
}
}
return hr;
}
STDAPI DllGetClassObject(REFCLSID rclsid ,REFIID riid,void **ppv)
{
if(rclsid == CLSID_TimeBeijingClass)
{
TimeBeijingClassFactory *pFactory = new TimeBeijingClassFactory;
if(pFactory == NULL)
return E_OUTOFMEMORY;
HRESULT hr = pFactory->QueryInterface(riid, ppv);
return hr;
}
return CLASS_E_CLASSNOTAVAILABLE;
}
STDAPI DllCanUnloadNow(void)
{
return ( g_cObjectAndLocks == 0 )
? S_OK : E_FAIL;
}
(六)DEF文件
LIBRARY "TimeBeijing.DLL"
EXPORTS
DllCanUnloadNow @1 PRIVATE
DllGetClassObject @2 PRIVATE
DllRegisterServer @3 PRIVATE
DllUnregisterServer @4 PRIVATE
(七)测试程序
#include "../TimeBeijing.h"
#include "../TimeBeijing_i.c"
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
HRESULT hr = CoInitialize(0);//初始化COM
int h, m, s;
ITimeBeijing * pTimeBeijing = NULL;
hr = ::CoCreateInstance(CLSID_TimeBeijingClass, //获取接口指针
NULL,
CLSCTX_INPROC,
IID_ITimeBeijing,
(void**)&pTimeBeijing);
if(SUCCEEDED(hr))
{
pTimeBeijing->GetTimeBeijing(&h, &m, &s);//调用接口
printf("当前时间:%d : %d : %d/n", h, m, s);
}
pTimeBeijing->Release();//释放接口
CoUninitialize();
system("pause");
return 0;
}
(八)测试结果
在命令行下输入:regsvr32 TimeBeijing.dll 启动服务器。
执行测试程序,结果如下:
TimeBeijingClassFactory - constructor
TimeBeijingClassFactory - QueryInterface
TimeBeijingClassFactory - AddRef
TimeBeijingClassFactory - CreateInstance
TimeBeijingClass - constructor
TimeBeijingClass - QueryInterface
TimeBeijingClass - AddRef
TimeBeijingClass - AddRef
TimeBeijingClass - Release
TimeBeijingClassFactory - Release
TimeBeijingClass - QueryInterface
TimeBeijingClass - AddRef
TimeBeijingClass - Release
TimeBeijingClass - GetTimeBeijing
当前时间:15 : 27 : 42
TimeBeijingClass - Release
TimeBeijingClass - destructor
请按任意键继续 . . .