如何更好地初始化不可创建的 COM 对象的引用计数器?

2023-12-19

我有一个 COM 接口,其中有一个返回对象的方法:

interface ICreatorInterface {
    HRESULT CreateObject( IObjectToCreate** );
};

关键是调用ICreatorInterface::CreateObject()是检索对象实现的唯一方法IObjectToCreate界面。

在 C++ 中我可以这样做:

 HRESULT CCreatorInterfaceImpl::CreateObject( IObjectToCreate** result )
 {
     //CObjectToCreateImpl constructor sets reference count to 0
     CObjectToCreateImpl* newObject = new CObjectToCreateImpl();
     HRESULT hr = newObject->QueryInterface( __uuidof(IObjectToCreate), (void**)result );
     if( FAILED(hr) ) {
         delete newObject;
     }
     return hr;
 }

或者这样

 HRESULT CCreatorInterfaceImpl::CreateObject( IObjectToCreate** result )
 {
     //CObjectToCreateImpl constructor sets reference count to 1
     CObjectToCreateImpl* newObject = new CObjectToCreateImpl();
     HRESULT hr = newObject->QueryInterface( __uuidof(IObjectToCreate), (void**)result );
     // if QI() failed reference count is still 1 so this will delete the object
     newObject->Release();
     return hr;
 }

不同之处在于引用计数器的初始化方式以及万一情况下对象删除的实现方式QueryInterface()失败。因为我完全控制两者CCreatorInterfaceImpl and CObjectToCreateImpl我可以选择任何一种方式。

IMO 第一个变体更清晰 - 所有引用计数的东西都在一段代码中。我有监督什么吗?为什么第二种方法会更好?以上哪一个更好,为什么?


这两种变体都违反了 COM 的一个非常基本的原则

  • 切勿对引用计数为零的 COM 对象调用除 AddRef 之外的任何方法。

否则会导致各种错误。简单地说,因为它阻止人们对对象进行完全合法的操作。就像把它们放入智能指针一样。智能指针将调用 AddRef,将计数设置为 1,然后 Release 将计数设置为 0 并导致对象自毁。

是的,我意识到 90% 的 QueryInterface 实现都没有这样做。但我也向你保证,有一些可以做到:)

我认为最简单的方法是在创建对象后立即调用 AddRef。这允许对象尽早表现得像普通 COM 对象一样。

我过去遇到过这个问题,并且编写了一个很好的小帮助器方法(假设该对象是在 ATL 中实现的)。

template <class T>
static 
HRESULT CreateWithRef(T** ppObject)
{
    CComObject<T> *pObject;
    HRESULT hr = CComObject<T>::CreateInstance(&pObject);
    if ( SUCCEEDED(hr) )
    {
        pObject->AddRef();
        *ppObject = pObject;
    }

    return hr; 
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何更好地初始化不可创建的 COM 对象的引用计数器? 的相关文章

随机推荐

  • 提取数据库对象的代码或脚本

    我需要从所有函数 过程 包 视图和表中提取代码 脚本 以便当我转向生产时我可以运行脚本来创建所有对象 在开发过程中 我没有对所有数据库对象进行脚本备份 提取代码或脚本的最佳方法是什么 任何建议或帮助都非常值得赞赏 Thanks 您确实使用版
  • 我可以将值为“未定义”的字符串转换为实际的未定义吗?

    当我从前端发出 GET 请求时 我将几个查询参数应用于 URL 如下所示 let response await axios get products searchQuery this searchQuery categoryId this
  • 调用结构体的方法

    这段代码工作正常 feedService postgres FeedService feeds err feedService GetAllRssFeeds 但这段代码给了我错误 feeds err postgres FeedService
  • Bootstrap:向导航栏添加按钮组?

    添加一个是否足够容易btn group to navbar in bootstrap btn很好 但不太好 当btn group div 在Bootstrap3中 您可以添加一个navbar btn类给你的按钮让它们垂直对齐 即使在btn
  • Android中可以使用哪些编程语言进行开发? [复制]

    这个问题在这里已经有答案了 可能的重复 我可以在 Android Dalvik 上使用哪些编程语言 https stackoverflow com questions 1994703 which programming languages
  • 计算百分比Javascript

    我有一个关于 JavaScript 逻辑的问题 我用什么来从文本字段获取两个输入的百分比 这是我的代码 var pPos pointspossible val var pEarned pointsgiven val var perc pEa
  • R 中的部分合并

    在我最终达到 7之前r中数据帧之间的两两匹配 https stackoverflow com questions 12123013 two by two matching between dataframes in r是的 让我说我已经阅读
  • Android textview html 字体大小标签

    I use font size 4 android textview 中的标签像这样 resultTextView setText Html fromHtml font size 4 color 337744 Text Message fo
  • 突出显示缓冲区修改

    文件缓冲区经常被修改 废话 退出之前 emacs 会询问是否保存更改 现在了解到底发生了什么变化将会很有趣 有办法找出来吗 As of Emacs 22 1 at least save buffers kill emacs the defa
  • MigraDoc 表超出了第 2 页的标题?

    您好 我在 MigraDoc 中制作了一个大型表格 当表格对于页面而言太大时 它会自动拆分表格 我的页眉中有一个徽标 当我的表格转到第 2 页时 它位于徽标上方 而不是在徽标下方 有人知道如何确保它在移动到其他页面时消失吗 这是徽标代码 就
  • ModuleNotFoundError:没有名为“setuptools._distutils”的模块

    当我在 python 中安装以下包时遇到异常 pip install django microsoft auth 例外 ModuleNotFoundError No module named setuptools distutils 这里有
  • 为 Android 手机和平板电脑创建不同的布局

    这是一个基本的安卓问题 我的应用程序需要为手机和平板电脑提供不同的屏幕设计 手机需要有一个 ListView 平板电脑需要有一个项目的 GridView 我想知道如何在不制作两个不同的应用程序的情况下做到这一点 Thanks 基本上你必须为
  • C++ 控制台屏幕尺寸

    所以我在大学里学习了一些关于 C 的东西 我和老师就如何将文本实际居中到输出屏幕进行了讨论 所以我的建议是使用setw但得到字符串的长度和size在控制台屏幕上 进行算法和 BAM 我们就有了真正居中的文本 他说屏幕尺寸是80但屏幕可以调整
  • 清单文件无效

    我成功上传了扩展程序的新版本到 Chrome 应用程序 https chrome google com webstore detail producteev auto login dbmjalgigkhfhmckigghggodkafpfd
  • 是否可以使用默认的 Windows 凭据以非交互方式对远程 Git 存储库进行身份验证?

    我的远程 Git 存储库由本地 TFS 服务器托管 有两种方法可以访问其内容 使用 TFS Restful API https learn microsoft com en us rest api vsts git items get vi
  • Microsoft Graph API 用于读取分配给 Teams 用户的电话号码

    是否有任何 MS Graph API 可以读取分配给 Teams 用户的电话号码以进行直接路由 请通过 它返回一组默认属性businessPhones displayName givenName id mobilePhone officeL
  • 检查消息类型时避免使用instanceof

    我遇到以下情况 客户端类根据它收到的消息类型执行不同的行为 我想知道是否有更好的方法来做到这一点 因为我不喜欢 instanceof 和 if 语句 我想做的一件事是将方法从客户端类中取出并将它们放入消息中 我会将类似 process 的方
  • 哪些请求标头可用于浏览器/客户端指纹?

    为了增加安全性 我们的服务器会跟踪浏览器指纹 目前我们使用以下标头 HTTP CLIENT IP HTTP X FORWARDED FOR HTTP X FORWARDED HTTP X CLUSTER CLIENT IP HTTP FOR
  • Android Studio 中出现“jcenter.bintray.com:443 未能响应”错误

    我正在尝试在 Android Studio 中构建一个项目 而 Android 的默认构建工具 Gradle 在尝试构建我的项目时总是给我一个错误 以下是使用 gradlew build 命令的结果 FAILURE Build failed
  • 如何更好地初始化不可创建的 COM 对象的引用计数器?

    我有一个 COM 接口 其中有一个返回对象的方法 interface ICreatorInterface HRESULT CreateObject IObjectToCreate 关键是调用ICreatorInterface CreateO