COM组件例子程序源代码路径:https://download.csdn.net/download/xiaoyafang123/10741052
此例子程序既创建了进程内组件,又创建了经常外组件。包括4个工程项目:
DictCtrl为客户程序工程
Dictionary为进程外组件工程
Dictionary2为进程内组件工程
DictPrxy为代理/存根dll工程
下面我们分别介绍各个工程(详细的源代码请下载源码自己看,这里只是介绍一下重点要注意的地方):
DictPrxy工程(代理/存根dll):
首先这个工程定义了接口声明文件Dictionary.idl:
import "unknwn.idl";
#define MaxWordLength 32
[
object,
uuid(54BF6568-1007-11D1-B0AA-444553540000),
pointer_default(unique)
]
interface IDictionary : IUnknown
{
HRESULT Initialize();
HRESULT LoadLibrary([in, string] WCHAR *pFilename);
HRESULT InsertWord([in, string] WCHAR *pWord, [in, string] WCHAR *pWordUsingOtherLang);
HRESULT DeleteWord([in, string] WCHAR *pWord);
HRESULT LookupWord([in, string] WCHAR *pWord, [out] WCHAR pWordOut[MaxWordLength]);
HRESULT RestoreLibrary([in, string] WCHAR *pFilename);
HRESULT FreeLibrary();
};
[
object,
uuid(54BF6569-1007-11D1-B0AA-444553540000),
pointer_default(unique)
]
interface ISpellCheck : IUnknown
{
HRESULT CheckWord([in, string] WCHAR *pWord, [out] WCHAR pWordOut[MaxWordLength]);
};
根据这个文件,我们可以生成Dictionary_h.h,Dictionary_i.c,Dictionary_p.c,dlldata.c文件。
Dictionary_h.h:接口声明都在这里面
Dictionary_i.c GUID的定义都在这个文件里面
Dictionary_p.c,dlldata.c 生成代理/存根dll依赖这2个文件
通过这几个文件和导出函数文件(DictPrxy.def),我们可以生成代理/存根dll。
DictPrxy.def文件定义如下:
LIBRARY DictPrxy
DESCRIPTION 'IDictionary Interface Proxy/Stub DLL'
EXPORTS
DllGetClassObject @1 PRIVATE
DllCanUnloadNow @2 PRIVATE
GetProxyDllInfo @3 PRIVATE
DllRegisterServer @4 PRIVATE
DllUnregisterServer @5 PRIVATE
后面几个工程都有用到这个工程生成的文件Dictionary_h.h,Dictionary_i.c。
DictCtrl工程(客户调用程序):
如果客户程序想创建进程外组件,调用代码如下:
hResult = CoCreateInstance(dictionaryCLSID, NULL,
CLSCTX_LOCAL_SERVER, IID_IUnknown, (void **)&pUnknown);
如果客户程序想创建进程内组件,调用代码如下:
hResult = CoCreateInstance(dictionaryCLSID, NULL,
CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&pUnknown);
Dictionary工程(进程外组件):
此工程不需要导出函数,但是也需要注册/注销,组件程序启动以后还要注册类厂对象,组件程序关闭之前还要注销类厂对象。
winmain函数如下:
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// Initialize the COM Library.
HRESULT hr = CoInitialize(NULL) ;
if (FAILED(hr))
{
return 0 ;
}
int retVal = 0;
// If TRUE, don't loop.
BOOL bExit = FALSE ;
// Read the command line.
char szTokens[] = "-/" ;
dwMainThreadID = ::GetCurrentThreadId() ;
char* szToken = strtok(lpCmdLine, szTokens) ;
while (szToken != NULL)
{
if (_stricmp(szToken, "RegServer") == 0)
{
char szModule[1024];
DWORD dwResult = ::GetModuleFileName((HMODULE)hInstance, szModule, 1024);
if (dwResult == 0)
retVal = SELFREG_E_CLASS;
retVal = RegisterServer(CLSID_Dictionary,
szModule,
"Dictionary.Object",
"Dictionary Component",
NULL);
// We are done, so exit.
bExit = TRUE ;
}
else if (_stricmp(szToken, "UnregServer") == 0)
{
retVal = UnregisterServer(CLSID_Dictionary,
"Dictionary.Object",NULL);
// We are done, so exit.
bExit = TRUE ;
}
else if (_stricmp(szToken, "Embedding") == 0)
{
bExit = FALSE;
break ;
}
szToken = strtok(NULL, szTokens) ;
}
if (!bExit)
{
// Register all of the class factory.
CDictionaryFactory::RegisterFactory();
// Wait for shutdown.
MSG msg ;
while (::GetMessage(&msg, 0, 0, 0))
{
::DispatchMessage(&msg);
}
// Unregister the class factory.
CDictionaryFactory::UnregisterFactory() ;
}
// Uninitialize the COM Library.
CoUninitialize() ;
return 0 ;
}
此外还要注意注册函数要修改一个地方,将注册的键改为:LocalServer32
SetKeyAndValue(szKey, "LocalServer32", szFileName) ;
Dictionary2工程(进程内组件):
进程内组件需要导出4个函数,主要代码如下:
HMODULE g_hModule;
extern ULONG g_LockNumber;
extern ULONG g_DictionaryNumber;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_hModule = hModule;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C" const GUID CLSID_Dictionary =
{ 0x54bf6567, 0x1007, 0x11d1,
{ 0xb0, 0xaa, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } };
extern "C" HRESULT __stdcall DllGetClassObject(const CLSID& clsid, const IID& iid, void **ppv)
{
if (clsid == CLSID_Dictionary) {
CAFactory *pFactory = new CAFactory;
if (pFactory == NULL) {
return E_OUTOFMEMORY;
}
HRESULT result = pFactory->QueryInterface(iid, ppv);
return result;
}
else {
return CLASS_E_CLASSNOTAVAILABLE;
}
}
extern "C" HRESULT __stdcall DllCanUnloadNow(void)
{
if ((g_DictionaryNumber == 0) && (g_LockNumber == 0))
return S_OK;
else
return S_FALSE;
}
//
// Server registration
//
extern "C" HRESULT __stdcall DllRegisterServer()
{
char szModule[1024];
DWORD dwResult = ::GetModuleFileName((HMODULE)g_hModule, szModule, 1024);
if (dwResult == 0)
return E_FAIL;
return RegisterServer(CLSID_Dictionary,
szModule,
"Dictionary.Object",
"Dictionary Component",
NULL);
}
//
// Server unregistration
//
extern "C" HRESULT __stdcall DllUnregisterServer()
{
return UnregisterServer(CLSID_Dictionary,
"Dictionary.Object", NULL);
}
此外还要注意注册函数要修改一个地方,将注册的键改为:InprocServer32
SetKeyAndValue(szKey, "InprocServer32", szFileName) ;
此例子程序可以支持进程内组件和进程外组件同时注册,组成完以后,注册表如下:
InprocServer32为进程内组件注册的。
LocalServer32为进程外组件注册的。