com学习记录(二)——使用vs2019完成windows下的com组件编程

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;

}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值