[com]使用VS2022创建一个自定义com组件--C++

这篇具有很好参考价值的文章主要介绍了[com]使用VS2022创建一个自定义com组件--C++。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文是在《C++ COM组件的编写》的基础上做了一些细节上的增添,可以让像我这样的资质驽钝者可以减少一点学习障碍。

新建一个dll项目

新建项目分两步即可
1.创建新项目,选择动态链接库(dll)
[com]使用VS2022创建一个自定义com组件--C++
2. 填写com组件名称,修改项目路径,最后创建
[com]使用VS2022创建一个自定义com组件--C++
创建后文件组织如图所示, framework.h和pch.h,pch.cpp不用管,保持原样即可,dllmain.cpp后面需要进行修改,或者说屏蔽。
[com]使用VS2022创建一个自定义com组件--C++

添加代码

需要添加的代码参考文献里已经有了,后面我会再贴一下,因为参考文献里面的时间有点久远,已经无法直接复制了,而且个别代码有些问题需要修正,但主体没有问题。
头文件需要添加三个,分别为ICompTest.h,定义接口,CompTestClass.h实现接口,factory.h定义工厂类
[com]使用VS2022创建一个自定义com组件--C++
源文件需要添加三个,factory.cpp实现工厂类,CompTestClass.cpp实现接口,CompTest.cpp实现的是注册,反注册,获取对象什么的。
[com]使用VS2022创建一个自定义com组件--C++
在工程所在目录创建一个文件,命名为mydef.def,内容会贴在后面
[com]使用VS2022创建一个自定义com组件--C++
创建好文件后要添加到项目中,添加路径如下:右键项目->属性->链接器->输入->模块定义文件,手动输入
[com]使用VS2022创建一个自定义com组件--C++

编译运行

编译时会报错DllMain函数重定义,这个时候需要将dllMain.cpp里面的这个函数定义注释掉就可以了

注册

注册命令:regsvr32.exe ComTest2.dll
反注册命令:regsvr32.exe ComTest2.dll -u

管理员启动cmd,切换到库所在路径,运行注册命令,成功后注册表如图所示:
[com]使用VS2022创建一个自定义com组件--C++
[com]使用VS2022创建一个自定义com组件--C++

测试

新建一控制台程序,输入如下代码作为客户端:

#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) {
        printf("Can't find CLSID!\n");
        return -1;
    }
    else {
        LPOLESTR szCLSID;
        StringFromCLSID(CLSID_CompTestClass, &szCLSID);     //将其转化为字符串形式用来输出  
        wprintf(L"find CLSID \"%s\"\n", szCLSID);
        CoTaskMemFree(szCLSID);     //调用COM库的内存释放  
    }

    //用此CLSID创建一个COM对象并获取IUnknown接口  
    hResult = CoCreateInstance(CLSID_CompTestClass, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);

    if (S_OK != hResult || NULL == pUnknown) {
        printf("Create Object Failed!\n");
        return -1;
    }

    ICompTest* pCompTest = NULL;
    hResult = pUnknown->QueryInterface(IID_ICompTest, (void**)&pCompTest);//通过此结构查询我们自己的ICompTest接口  

    cout << pCompTest->HelloWorld() << endl;//调用我们自己接口中的函数  
    pCompTest->Release();    //释放自己的接口  
    pUnknown->Release(); //释放IUnknown接口  
    CoUninitialize();       //COM库反初始化  
    return 0;
}

运行结果如图:
[com]使用VS2022创建一个自定义com组件--C++

源码

ICompTest.h

//ICompTest.h
#pragma once
#include <unknwn.h>  

// {81A80687-6CC4-4996-8DD2-F058907FDCA8}  
static const GUID IID_ICompTest =
{ 0x81a80687, 0x6cc4, 0x4996, { 0x8d, 0xd2, 0xf0, 0x58, 0x90, 0x7f, 0xdc, 0xa8 } };


class ICompTest :
    public IUnknown
{
public:
    virtual int _stdcall HelloWorld() = 0;
};

CompTestClass.h

//CompTestClass.h
#pragma once

#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();
     
    ULONG ObjNum();
    static int Init();
protected:

    ULONG m_Ref;
public:
    static ULONG m_objNum;
    static CRITICAL_SECTION m_cs;
};

factory.h

//factory.h
#pragma once
#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接口  
    virtual HRESULT _stdcall CreateInstance(IUnknown* pUnkOuter, const IID& riid, void** ppvObject);
    virtual HRESULT _stdcall LockServer(BOOL fLock);

protected:
    ULONG m_Ref;
};

CompTestClass.cpp

//CompTestClass.cpp
#include "pch.h"
#include "CompTestClass.h"  


ULONG CompTestClass::m_objNum = 0;//组件中CompTestClass对象的个数,用于判断是否可以卸载本组建,如值为0则可以卸载  
CRITICAL_SECTION CompTestClass::m_cs;//为了多线程调用对m_objNum加的锁  

CompTestClass::CompTestClass()
{
    m_Ref = 0;
    //autoLock tlock(m_cs);
    m_objNum++;    //构造了一个对象  
}

CompTestClass::~CompTestClass()
{
    //autoLock tlock(m_cs);
    m_objNum--;    //释放了一个对象  
}

HRESULT _stdcall CompTestClass::QueryInterface(const IID& riid, void** ppvObject)
{
    if (IID_IUnknown == riid) {
        *ppvObject = (IUnknown*)this;
        ((IUnknown*)(*ppvObject))->AddRef();
    }
    else if (IID_ICompTest == riid) {
        *ppvObject = (ICompTest*)this;
        ((ICompTest*)(*ppvObject))->AddRef();
    }
    else {
        *ppvObject = NULL;
        return E_NOINTERFACE;
    }
    return S_OK;
}

ULONG _stdcall CompTestClass::AddRef()
{
    m_Ref++;
    return m_Ref;
}

ULONG _stdcall CompTestClass::Release()
{
    m_Ref--;
    if (0 == m_Ref) {
        delete this;
        return 0;
    }
    return m_Ref;
}

int _stdcall CompTestClass::HelloWorld()//ICompTest接口的实现,返回一个整数89  
{
    return 89;
}

int CompTestClass::Init()
{
    m_objNum = 0;
    InitializeCriticalSection(&m_cs);
    return 0;
}

ULONG CompTestClass::ObjNum()
{
    return m_objNum;
}

factory.cpp

//factory.cpp
#include "pch.h"
#include "factory.h"  
#include "CompTestClass.h"  


CompTestFactory::CompTestFactory()
{
    m_Ref = 0;
}

CompTestFactory::~CompTestFactory()
{

}

HRESULT _stdcall CompTestFactory::QueryInterface(const IID& riid, void** ppvObject)
{
    if (IID_IUnknown == riid) {
        *ppvObject = (IUnknown*)this;
        ((IUnknown*)(*ppvObject))->AddRef();
    }
    else if (IID_IClassFactory == riid) {
        *ppvObject = (IClassFactory*)this;
        ((IClassFactory*)(*ppvObject))->AddRef();
    }
    else {
        *ppvObject = NULL;
        return E_NOINTERFACE;
    }
    return S_OK;
}

ULONG _stdcall CompTestFactory::AddRef()
{
    m_Ref++;
    return m_Ref;
}

ULONG _stdcall CompTestFactory::Release()
{
    m_Ref--;
    if (0 == m_Ref) {
        delete this;
        return 0;
    }
    return m_Ref;
}

HRESULT _stdcall CompTestFactory::CreateInstance(IUnknown* pUnkOuter, const IID& riid, void** ppvObject)//最重要的函数,这个函数创建CompTestClass对象,并返回所需接口  
{
    if (NULL != pUnkOuter) {
        return CLASS_E_NOAGGREGATION;
    }
    HRESULT hr = E_OUTOFMEMORY;
    CompTestClass::Init();
    CompTestClass* pObj = new CompTestClass();
    if (NULL == pObj) {
        return hr;
    }

    hr = pObj->QueryInterface(riid, ppvObject);
    if (S_OK != hr) {
        delete pObj;
    }
    return hr;
}

HRESULT _stdcall CompTestFactory::LockServer(BOOL fLock)
{
    return NOERROR;
}

CompTest.cpp

//CompTest.cpp
#include "pch.h"
#include <iostream>  
#include <windows.h>  

#include "factory.h"  
#include "CompTestClass.h"  


using namespace std;

HMODULE g_hModule;  //dll进程实例句柄  
ULONG g_num;        //组件中CompTestClass对象的个数,用于判断是否可以卸载本组建,如值为0则可以卸载  

int myReg(LPCWSTR lpPath)   //将本组件的信息写入注册表,包括CLSID、所在路径lpPath、ProgID  
{
    HKEY thk, tclsidk;

    //打开键HKEY_CLASSES_ROOT\CLSID,创建新键为CompTestClass的CLSID,  
    //在该键下创建键InprocServer32,并将本组件(dll)所在路径lpPath写为该键的默认值  
    if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, L"CLSID", &thk)) {
        if (ERROR_SUCCESS == RegCreateKey(thk, L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}", &tclsidk)) {
            HKEY tinps32k, tprogidk;
            if (ERROR_SUCCESS == RegCreateKey(tclsidk, L"InprocServer32", &tinps32k)) {
                if (ERROR_SUCCESS == RegSetValue(tinps32k, NULL, REG_SZ, lpPath, wcslen(lpPath) * 2)) {
                }
                RegCloseKey(tinps32k);
            }
            RegCloseKey(tclsidk);
        }
        RegCloseKey(thk);
    }
    //在键HKEY_CLASSES_ROOT下创建新键为COMCTL.CompTest,  
    //在该键下创建子键,并将CompTestClass的CLSID写为该键的默认值  
    if (ERROR_SUCCESS == RegCreateKey(HKEY_CLASSES_ROOT, L"COMCTL.CompTest", &thk)) {
        if (ERROR_SUCCESS == RegCreateKey(thk, L"CLSID", &tclsidk)) {
            if (ERROR_SUCCESS == RegSetValue(tclsidk,
                NULL,
                REG_SZ,
                L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}",
                wcslen(L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}") * 2)) {
            }
        }
    }
    //这样的话一个客户端程序如果想要使用本组件,首先可以以COMCTL.CompTest为参数调用CLSIDFromProgID函数  
    //来获取CompTestClass的CLSID,再以这个CLSID为参数调用CoCreateInstance创建COM对象  
    return 0;
}

extern "C" HRESULT _stdcall DllRegisterServer()
{
    WCHAR szModule[1024];

   
    DWORD dwResult = GetModuleFileName(g_hModule, szModule, 1024); //获取本组件(dll)所在路径  
    WCHAR szModule1[1024] = { 'b','e','g', 'i', 'n', '\0'};
    MessageBox(NULL, szModule1, L"", MB_OK);
    if (0 == dwResult) {
        return -1;
    }
    MessageBox(NULL, szModule, L"", MB_OK);
    myReg(szModule);//将路径等信息写入注册表  
    return 0;
}

int myDelKey(HKEY hk, LPCWSTR lp)
{
    if (ERROR_SUCCESS == RegDeleteKey(hk, lp)) {
    }
    return 0;
}

int myDel() //删除注册时写入注册表的信息  
{
    HKEY thk;
    if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, L"CLSID", &thk)) {
        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)) {
        myDelKey(thk, L"CLSID");
    }
    myDelKey(HKEY_CLASSES_ROOT, L"COMCTL.CompTest");
    return 0;
}

extern "C" HRESULT _stdcall DllUnregisterServer()
{
    myDel();//删除注册时写入注册表的信息  

    return 0;
}

STDAPI  DllCanUnloadNow(void)//用于判断是否可以卸载本组建, 由CoFreeUnusedLibraries函数调用  
{
    if (0 == g_num) {//如果对象个数为0,则可以卸载  
        return S_OK;
    }
    else {
        return S_FALSE;
    }
    return S_OK;
}



STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID FAR * ppv)//用于创建类厂并返回所需接口,由CoGetClassObject函数调用  
{
    WCHAR szModule1[1024] = { 'b','e','g', 'i', 'n', '  ', 'g', 'e', 't', 'c', 'l', ' \0' };
    szModule1[11] = '\0';
    MessageBox(NULL, szModule1, L"", MB_OK);
    if (CLSID_CompTestClass == rclsid) {
        CompTestFactory* pFactory = new CompTestFactory();//创建类厂对象  
        if (NULL == pFactory) {
            return E_OUTOFMEMORY;
        }
        HRESULT result = pFactory->QueryInterface(riid, ppv);//获取所需接口  
        return result;
    }
    else {
        return CLASS_E_CLASSNOTAVAILABLE;
    }
    return S_OK;
}




BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    g_hModule = hModule;  //dll进程实例句柄  
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

mydef.def文章来源地址https://www.toymoban.com/news/detail-509978.html

//mydef.def
LIBRARY "CompTest"
EXPORTS
DllCanUnloadNow
DllGetClassObject
DllUnregisterServer
DllRegisterServer

到了这里,关于[com]使用VS2022创建一个自定义com组件--C++的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • VS解决 对COM组件的调用返回了错误HRESULT E_FAIL

    VS解决 对COM组件的调用返回了错误HRESULT E_FAIL

    第一步 运行Developer Command Prompt for VS 2019   在开始菜单中找到Developer Command Prompt for VS 2019 右键 以管理员身份运行。 程序运行后,会跳到默认的路径下。     第二部 跳转到跳转到 vs2019的安装目录下 我的vs的安装路径是在C盘,我的路径是:C:Program Files (x86)Microsoft Visual Studi

    2024年02月02日
    浏览(12)
  • VS2022默认创建类的访问修饰符为internal问题

    VS2022默认创建类的访问修饰符为internal问题

    由于创建类是根据模板文件生成的,所里这里我们需要修改以下vs自带的模板 找到模板位置 通常情况位于C:Program FilesMicrosoft Visual Studio2022{安装的版本:比如(Preview,Professional等)}Common7IDEItemTemplatesCSharpCode2052 找到你要修改的类型模板 进入文件夹 修改.cs文件 如: 在class前加入

    2024年02月06日
    浏览(10)
  • 解决VS2022每次创建新工程都需要重新配置opencv的问题

    解决VS2022每次创建新工程都需要重新配置opencv的问题

    解决VS2022每次创建新工程都需要重新配置opencv的问题 事情起因是我按照网上其他配置opencv的教程配置opencv后,每次重新创建编程项目都需要再重新配置一遍opencv,搜了下解决方法也没有得到有效解决,最后参照老版本vs配置opencv的方法,终于解决了,解决方法如下: 首先问题

    2024年02月10日
    浏览(7)
  • VS2022 安装教程及第一个C#代码(社区版超详细)

    VS2022 安装教程及第一个C#代码(社区版超详细)

    找到VS下载官网 https://visualstudio.microsoft.com/zh-hans/downloads/ 下载社区版,直接点击下载保存即可 点击Community 下的免费下载,直接下载保存到文件夹中 下载后只有VisualStudioSetup.exe,VisualStudio文件夹是新建的文件夹,准备存放稍后安装的VisualStudio(大家根据自身习惯选择即可)

    2024年02月04日
    浏览(11)
  • 界面组件Telerik UI for WinForms R2 2023——拥有VS2022暗黑主题

    界面组件Telerik UI for WinForms R2 2023——拥有VS2022暗黑主题

    Telerik UI for WinForms拥有适用Windows Forms的110多个令人惊叹的UI控件。所有的UI for WinForms控件都具有完整的主题支持,可以轻松地帮助开发人员在桌面和平板电脑应用程序提供一致美观的下一代用户体验。 Telerik UI for WinForms R2 2023于今年6月份发布,此版本中集成了备受期待的Visu

    2024年02月12日
    浏览(11)
  • [C#]vs2022安装后C#创建winform没有.net framework4.8

    [C#]vs2022安装后C#创建winform没有.net framework4.8

    问题,我已经在visualstudio安装程序中安装了.net框架4.8的SDK和运行时。 然而,我在visual studio 2022中找不到已安装的框架。 我已经检查了我的VS 2019,它可以很好地定位网络框架4.8,它可以构建我的项目。但VS 2022不能。 我已经重新安装了VS 2022和VS 2019,但VS 2022仍然找不到我的框

    2024年02月07日
    浏览(12)
  • vs2017如何创建一个asax文件

    vs2017如何创建一个asax文件

    VS2017无法为网站创建Global.asax文件,导致出现错误WebForms UnobtrusiveValidationMode 需要“jquery”ScriptResourceMapping。 解决方案如下:   勾选要应用的网站,这里我要应用的是ExSite 点击安装,然后点击确定即可。    此时,就可以创建 Global.asax了。 右击要添加的网站:  接着,操作

    2024年02月03日
    浏览(8)
  • 使用Dockerfile构建自定义jdk镜像,在使用jdk镜像创建一个容器来外部访问(一步一步来哦~好简单的呢)

    使用Dockerfile构建自定义jdk镜像,在使用jdk镜像创建一个容器来外部访问(一步一步来哦~好简单的呢)

    文章主人公:帅哥BUG😎  文章路人: 路人 🤨  路人 😛 🤨:什么是dockerfile? 😎:Dockerfile 是一个文本格式的配置文件, 用户可以使用 Dockerfile 来快速创建自定义的镜像,另外,使 用Dockerfile去构建镜像好比使用pom去构建maven项目一样,有异曲同工之妙 😛:知道了知道了,

    2024年02月09日
    浏览(13)
  • vs2022使用单元测试

    vs2022使用单元测试

    点击上方工具栏的扩展选择管理扩展 选择联机 搜索mstest 点击MSTest v2 Template 注意安装的时候需要关闭 vs 1、右键点击解决方案 2、选择新建项 3、创建单元测试项目 4、引用需要测试的项目 5、编写测试代码 6、调试单元测试

    2024年02月13日
    浏览(20)
  • VS2022的下载和使用

    VS2022的下载和使用

    目录 一、VS2022的下载 二、VS的一些使用技巧 1.如何使用VS写代码 2.scanf函数在VS上的使用 3.下载后怎么安装新的工作负荷 4.VS的调试与监视功能 如何进行调试 如何进行监视 三、结语 VS官网链接 1.打开VS的官网链接,选择下载Visual Studio,选择社区版,点击下载。  2.工作负荷选

    2023年04月08日
    浏览(13)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包