com学习记录(一)——基本概念
com学习记录(二)——使用vs2019完成windows下的com组件编程
com学习记录(三)——在Linux环境下完成com组件编程
com学习记录(四)——在Linux环境下完成com组件编程分离服务端(动态库)客户端(可执行程序)
com组件c++代码编写
服务端工程,是一个dll;客户端工程,是一个控制台工程
服务端生成动态库
vs2019项目配置类型为动态库,编译代码后点击生成,生成解决方案。控制台出现输出成功1个,以及
注册动态库
regsvr32 D:\code\vs2019\CompTest\Debug\CompTest.dll
客户端运行
服务端CompTest:
CompTestClass.h factory.h ICompTest.h
CompTest.cpp CompTestClass.cpp factory.cpp mydef.def
客户端CtrlTest:
ICompTest.h
CtrlTest.cpp
服务端代码
-
CompTestClass.h
/* $file: CompTestClass.h $date: 2020年8月11日 $author: hehl $describe: $other: */ #ifndef __COMPTESTCLASS_H__ #define __COMPTESTCLASS_H__ #include "ICompTest.h" // {9CA9DBE8-C0B1-42c9-B6C7-856BE5756855} static const GUID CLSID_CompTestClass = { 0x9ca9dbe8, 0xc0b1, 0x42c9, { 0xb6, 0xc7, 0x85, 0x6b, 0xe5, 0x75, 0x68, 0x55 } }; class CompTestClass : public ICompTest { public: CompTestClass(); ~CompTestClass(); //要实现IUnknown接口 virtual HRESULT _stdcall QueryInterface(const IID& riid, void** ppvObject); virtual ULONG _stdcall AddRef(); virtual ULONG _stdcall Release(); //要实现ICompTest接口 virtual int _stdcall HelloWorld(); virtual void Test(); CRITICAL_SECTION m_cs; //为了多线程调用对m_objNum加的锁 int Init(); protected: ULONG m_Ref; ULONG m_objNum = 0; //组件中CompTestClass对象的个数,用于判断是否可以卸载本组建,如值为0则可以卸载 }; #endif
-
factory.h
/* $file: factory.h $date: 2020年8月11日 $author: hehl $describe: $other: */ #ifndef __FACTORY_H__ #define __FACTORY_H__ #include <unknwn.h> class CompTestFactory : public IClassFactory { public: CompTestFactory(); // 构造函数 ~CompTestFactory(); // 析构函数 // 要实现IUnknown接口 virtual HRESULT _stdcall QueryInterface(const IID& riid, void** ppvObject); virtual ULONG _stdcall AddRef(); virtual ULONG _stdcall Release(); // 要实现IClassFactory接口 基类IClassFactory的虚函数 virtual HRESULT _stdcall CreateInstance(IUnknown* pUnkOuter, const IID& riid, void** ppvObject); virtual HRESULT _stdcall LockServer(BOOL fLock); protected: ULONG m_Ref; }; #endif
-
ICompTest.h
/* $file: ICompTest.h $date: 2020年8月11日 $author: hehl $describe: $other: */ #ifndef __ICOMPTEST_H__ #define __ICOMPTEST_H__ #include <unknwn.h> // {81A80687-6CC4-4996-8DD2-F058907FDCA9} static const GUID IID_ICompTest = { 0x81a80687, 0x6cc4, 0x4996, { 0x8d, 0xd2, 0xf0, 0x58, 0x90, 0x7f, 0xdc, 0xa9 } }; class ICompTest : public IUnknown { public: virtual int _stdcall HelloWorld() = 0; virtual void Test() = 0; }; #endif // !__ICOMPTEST_H__
-
CompTest.cpp
/* $file: CompTest.cpp $date: 2020年8月11日 $author: hehl $describe: $other: */ #include <iostream> //#include <windows.h> #include "factory.h" #include "CompTestClass.h" using namespace std; HMODULE g_hModule; // dll进程实例句柄 ULONG g_num; // 组件中CompTestClass对象的个数,用于判断是否可以卸载本组建,如值为0则可以卸载 // 将本组件的信息写入注册表,包括CLSID、所在路径lpPath、ProgID int myReg(LPCWSTR lpPath) { HKEY thk, tclsidk; cout << "myReg() in" << endl; // 打开键HKEY_CLASSES_ROOT\CLSID,创建新键为CompTestClass的CLSID, // 在该键下创建键InprocServer32,并将本组件(dll)所在路径lpPath写为该键的默认值 if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, L"CLSID", &thk)) { cout << "myReg() ERROR_SUCCESS == RegOpenKey" << endl; if (ERROR_SUCCESS == RegCreateKey(thk, L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}", &tclsidk)) { cout << "myReg() ERROR_SUCCESS == RegCreateKey" << endl; HKEY tinps32k; //HKEY tprogidk; if (ERROR_SUCCESS == RegCreateKey(tclsidk, L"InprocServer32", &tinps32k)) { cout << "myReg() ERROR_SUCCESS == RegCreateKey2" << endl; if (ERROR_SUCCESS == RegSetValue(tinps32k, NULL, REG_SZ, lpPath, wcslen(lpPath) * 2)) { cout << "myReg() ERROR_SUCCESS == RegSetValue" << endl; } RegCloseKey(tinps32k); } RegCloseKey(tclsidk); } RegCloseKey(thk); } // 在键HKEY_CLASSES_ROOT下创建新键为COMCTL.CompTest, // 在该键下创建子键,并将CompTestClass的CLSID写为该键的默认值 if (ERROR_SUCCESS == RegCreateKey(HKEY_CLASSES_ROOT, L"COMCTL.CompTest", &thk)) { cout << "myReg() ERROR_SUCCESS == RegCreateKey3" << endl; if (ERROR_SUCCESS == RegCreateKey(thk, L"CLSID", &tclsidk)) { cout << "myReg() ERROR_SUCCESS == RegCreateKey4" << endl; if (ERROR_SUCCESS == RegSetValue(tclsidk, NULL, REG_SZ, L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}", wcslen(L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}") * 2)) { cout << "myReg() ERROR_SUCCESS == RegSetValue2" << endl; } } } // 这样的话一个客户端程序如果想要使用本组件,首先可以以COMCTL.CompTest为参数调用CLSIDFromProgID函数 // 来获取CompTestClass的CLSID,再以这个CLSID为参数调用CoCreateInstance创建COM对象 return 0; } extern "C" HRESULT _stdcall DllRegisterServer() { cout << "DllRegisterServer() in" << endl; WCHAR szModule[1024]; DWORD dwResult = GetModuleFileName(g_hModule, szModule, 1024); // 获取本组件(dll)所在路径 if (0 == dwResult) { return -1; } MessageBox(NULL, szModule, L"", MB_OK); myReg(szModule); // 将路径等信息写入注册表 cout << "DllRegisterServer() out" << endl; return 0; } int myDelKey(HKEY hk, LPCWSTR lp) { cout << "myDelKey() in" << endl; if (ERROR_SUCCESS == RegDeleteKey(hk, lp)) { } return 0; } int myDel() // 删除注册时写入注册表的信息 { HKEY thk; cout << "myDel() in" << endl; if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, L"CLSID", &thk)) { cout << "myDel() ERROR_SUCCESS == RegOpenKey" << endl; myDelKey(thk, L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}\\InprocServer32"); myDelKey(thk, L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}"); RegCloseKey(thk); } if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, L"COMCTL.CompTest", &thk)) { cout << "myDel() ERROR_SUCCESS == RegOpenKey2" << endl; myDelKey(thk, L"CLSID"); } myDelKey(HKEY_CLASSES_ROOT, L"COMCTL.CompTest"); return 0; } extern "C" HRESULT _stdcall DllUnregisterServer() { cout << "DllUnregisterServer() in" << endl; myDel(); // 删除注册时写入注册表的信息 return 0; } extern "C" HRESULT _stdcall DllCanUnloadNow() // 用于判断是否可以卸载本组建, 由CoFreeUnusedLibraries函数调用 { cout << "DllCanUnloadNow() g_num:" << g_num << endl; if (0 == g_num) // 如果对象个数为0,则可以卸载 { return S_OK; } else { return S_FALSE; } } extern "C" HRESULT _stdcall DllGetClassObject(__in REFCLSID rclsid, __in REFIID riid, LPVOID FAR * ppv) // 用于创建类厂并返回所需接口,由CoGetClassObject函数调用 { if (CLSID_CompTestClass == rclsid) { cout << "DllGetClassObject() CLSID_CompTestClass == rclsid" << endl; CompTestFactory* pFactory = new CompTestFactory(); // 创建类厂对象 if (NULL == pFactory) { return E_OUTOFMEMORY; } HRESULT result = pFactory->QueryInterface(riid, ppv); // 获取所需接口 return result; } else { cout << "DllGetClassObject() else" << endl; return CLASS_E_CLASSNOTAVAILABLE; } } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { g_hModule = hModule; // 获取进程实例句柄,用于获取本组件(dll)路径 cout << "DllMain() ul_reason_for_call:" << ul_reason_for_call << endl; switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
-
CompTestClass.cpp
/* $file: CompTestClass.cpp $date: 2020年8月11日 $author: hehl $describe: $other: */ #include <iostream> #include "CompTestClass.h" using namespace std; // 构造函数 CompTestClass::CompTestClass() { m_Ref = 0; //autoLock tlock(m_cs); m_objNum++; // 构造了一个对象 cout << "CompTestClass() objNum:" << m_objNum << endl; } // 析构函数 CompTestClass::~CompTestClass() { // autoLock tlock(m_cs); m_objNum--; // 释放了一个对象 cout << "~CompTestClass() objNum:" << m_objNum << endl; } HRESULT _stdcall CompTestClass::QueryInterface(const IID& riid, void** ppvObject) { if (IID_IUnknown == riid) { cout << "CompTestClass::QueryInterfac() IID_IUnknown == riid" << endl; *ppvObject = (IUnknown*)this; ((IUnknown*)(*ppvObject))->AddRef(); } else if (IID_ICompTest == riid) { cout << "CompTestClass::QueryInterfac() IID_ICompTest == riid" << endl; *ppvObject = (ICompTest*)this; ((ICompTest*)(*ppvObject))->AddRef(); } else { cout << "CompTestClass::QueryInterfac() else" << endl; *ppvObject = NULL; return E_NOINTERFACE; } return S_OK; } ULONG _stdcall CompTestClass::AddRef() { m_Ref++; cout << "CompTestClass::AddRef() m_Ref:" << m_Ref << endl; return m_Ref; } ULONG _stdcall CompTestClass::Release() { m_Ref--; if (0 == m_Ref) { delete this; return 0; } cout << "CompTestClass::AddRef() Release:" << m_Ref << endl; return m_Ref; } int _stdcall CompTestClass::HelloWorld()//ICompTest接口的实现,返回一个整数89 { cout << "CompTestClass::HelloWorld()" << endl; return 656; } int CompTestClass::Init() { cout << "CompTestClass::Init()" << endl; m_objNum = 0; // InitializeCriticalSection(&m_cs); return 0; } void CompTestClass::Test() { cout << "CompTestClass::Test()" << endl; cout << "test by hhl" << endl; }
-
factory.cpp
/* $file: factory.cpp $date: 2020年8月11日 $author: hehl $describe: $other: */ #include <iostream> #include "factory.h" #include "CompTestClass.h" using namespace std; // 构造函数 CompTestFactory::CompTestFactory() { cout << "CompTestFactory()" << endl; m_Ref = 0; } // 析构函数 CompTestFactory::~CompTestFactory() { cout << "~CompTestFactory()" << endl; } // 从COM对象请求一个接口指针,查询接口 HRESULT _stdcall CompTestFactory::QueryInterface(const IID& riid, void** ppvObject) { if (IID_IUnknown == riid) { cout << "QueryInterface() IID_IUnknown == riid" << endl; *ppvObject = (IUnknown*)this; ((IUnknown*)(*ppvObject))->AddRef(); } else if (IID_IClassFactory == riid) { cout << "QueryInterface() IID_IClassFactory == riid" << endl; *ppvObject = (IClassFactory*)this; ((IClassFactory*)(*ppvObject))->AddRef(); } else { cout << "QueryInterface() else" << endl; *ppvObject = NULL; return E_NOINTERFACE; } return S_OK; } // 通知COM对象增加它的引用计数 ULONG _stdcall CompTestFactory::AddRef() { m_Ref++; cout << "AddRef() m_Ref:" << m_Ref << endl; return m_Ref; } // 通知COM对象减少它的引用计数 ULONG _stdcall CompTestFactory::Release() { m_Ref--; cout << "Release() m_Ref" << m_Ref << endl; if (0 == m_Ref) { delete this; return 0; } return m_Ref; } // 创建实例CompTestClass对象,并返回所需接口 HRESULT _stdcall CompTestFactory::CreateInstance(IUnknown* pUnkOuter, const IID& riid, void** ppvObject) { if (NULL != pUnkOuter) { return CLASS_E_NOAGGREGATION; } cout << "CreateInstance()" << endl; HRESULT hr = E_OUTOFMEMORY; //CompTestClass::Init(); CompTestClass *pObj = new CompTestClass(); // 创建一个CompTestClass对象 if (NULL == pObj) { cout << "CreateInstance() new CompTestClass error" << endl; return hr; } hr = pObj->QueryInterface(riid, ppvObject); cout << "pObj->QueryInterface result:" << hr << endl; if (S_OK != hr) { delete pObj; } return hr; } HRESULT _stdcall CompTestFactory::LockServer(BOOL fLock) { return NOERROR; }
-
Source.def
LIBRARY "CompTest" EXPORTS DllCanUnloadNow DllGetClassObject DllUnregisterServer DllRegisterServer
工程属性的配置类型为动态库(.dll)
工程里面的def文件新建时选择模块定义文件
客户端代码
-
ICompTest.h
/* $file: ICompTest.h $date: 2020年8月11日 $author: hehl $describe: $other: */ #ifndef __ICOMPTEST_H__ #define __ICOMPTEST_H__ #include <unknwn.h> // {81A80687-6CC4-4996-8DD2-F058907FDCA9} static const GUID IID_ICompTest = { 0x81a80687, 0x6cc4, 0x4996, \ { 0x8d, 0xd2, 0xf0, 0x58, 0x90, 0x7f, 0xdc, 0xa9 } }; class ICompTest : public IUnknown { public: virtual int _stdcall HelloWorld() = 0; virtual void Test() = 0; }; #endif // !__ICOMPTEST_H__
-
CtrlTest.cpp
/*
$file: CtrlTest.cpp
$date: 2020年8月11日
$author: hehl
$describe: COM客户端测试代码
$other:
*/
#include <iostream>
#include "ICompTest.h"
using namespace std;
int main()
{
CoInitialize(NULL); // 初始化COM库,使用默认的内存分配器
IUnknown* pUnknown = NULL;
GUID CLSID_CompTestClass;
HRESULT hResult = CLSIDFromProgID(L"COMCTL.CompTest", &CLSID_CompTestClass);
//获取ProgID为COMCTL.CompTest组建的CLSID
if (S_OK != hResult)
{
cout << "Can't find CLSID" << endl;
return -1;
}
else
{
LPOLESTR szCLSID;
StringFromCLSID(CLSID_CompTestClass, &szCLSID); // 将其转化为字符串形式用来输出
//wprintf(L"find CLSID \"%s\"\n", szCLSID);
cout << "find CLSID:" << szCLSID << endl;
CoTaskMemFree(szCLSID); // 调用COM库的内存释放
}
// 用此CLSID创建一个COM对象并获取IUnknown接口
hResult = CoCreateInstance(CLSID_CompTestClass, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);
if (S_OK != hResult || NULL == pUnknown)
{
cout << "Create Object Failed!" << endl;
return -1;
}
ICompTest* pCompTest = NULL;
// 通过此结构查询我们自己的ICompTest接口
hResult = pUnknown->QueryInterface(IID_ICompTest, (void**)&pCompTest);
cout << pCompTest->HelloWorld() << endl; // 调用我们自己接口中的函数
pCompTest->Test(); // 调用我们自己接口中的函数
pCompTest->Release(); // 释放自己的接口
pUnknown->Release(); // 释放IUnknown接口
CoUninitialize(); // COM库反初始化
return 0;
}