COM组件创建例子程序

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xiaoyafang123/article/details/83342729

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为进程外组件注册的。

展开阅读全文

没有更多推荐了,返回首页