Win32 COM编程纯C实现

6
我有一个编程项目,需要访问一些较低级别的Windows API(特别是WASAPI)。我对高级编程语言如C#,Java和PHP有相当丰富的经验,但对C / C ++只知道一点点。
我想在这个项目中使用C(而不是C ++),因为C ++有点可怕。在Visual Studio中更改项目的C / C ++设置以将其编译为C代码后,我注意到任何对 __uuidof 的调用都无法工作,因为它们是C ++特定的。
我的问题有两个方面:
  1. 是否可能编写纯C的Win32程序来利用COM,以及
  2. 如果可以,是否应避免使用纯C?

2
当然可以,但是使用C++会得到更多的内置支持。如果我没记错的话(我已经没有这本书了),Dale Rogerson的《Inside COM》从基础开始介绍COM——解释如何从纯C中访问它。 - Michael Burr
2
是的,我个人认为是这样的。在20年的COM编程中,我从未听说有人说他们更喜欢使用C,因为C++ COM编程很“可怕”。我两种语言都做过很长时间,但是C++要容易得多。你可以用C完成它,但是一旦你在C++中学习了最基本的实现方式,你会后悔没有用C++。(另外还要补充迈克尔的书单,回溯到Kraig Brockschmidt的Inside OLE2 =P)。 - WhozCraig
关于FQA的信息,请参阅之前的问题。简而言之:不要因为它吓到你而放弃C++;大部分都是无稽之谈。 - Jerry Coffin
2个回答

5
  1. 是的,使用纯C编写利用COM的程序是可能的,事实上在10-15年前这是常见做法。

  2. 使用C并不是一个好主意(正如你已经发现的那样)。例如,ATL在做COM时提供了很多帮助,并可以帮助您避免常见错误。

如果我是你,我会选择使用C++,即使门槛一开始可能有点高。此外,如果您没有书籍,则需要在该主题下获取一本。尽管无论您使用C还是C ++,COM编程都不是胆小的人所能轻易掌握的东西,网络上有许多示例可供使用,但最好有一些引导您入手。


4

COM使用的C++仅限于C部分的一个很小的子集,没有要求使用许多“可怕”的项目,例如:

  • 异常 - 如果你没有正确处理异常(需要真正理解RAII习惯,如果你习惯于更传统的C / Win32编程方式,则可能需要一些时间适应),那么在C ++中它们会让你非常困扰;但是异常并不是COM的一部分:COM使用返回代码进行所有错误处理。如果需要,有一些包装器和编译器扩展可以将COM的返回代码转换为C ++异常,但这是可选的。

  • 类层次结构和继承 - 继承实际上也不是COM本身的一部分,除了所有COM接口都派生自(或者说从)IUnknown开始的方法之外。但是您不需要了解任何关于多重虚拟继承的知识来使用 COM。如果您要实现COM对象,则了解其中一些内容非常有用,但仅使用它则不需要。(例如,使用C ++多重继承是实现公开多个接口的COM对象的非常常见的方法,但这不是唯一的方法。)

  • 模板 - 再次强调,不是COM的一部分,但有几个库 - 例如MFC和ATL - 使用模板使COM更加简单易用。特别是对于像CComPtr这样的智能指针类,它将为您处理一些引用计数,使您的代码可以集中精力做真正有趣的事情,而不是被包装在管理性任务中。

COM和C++之间的主要联系在于Windows上所有的C++编译器都可以将C++对象在内存中布局,以完全符合COM的要求。这使您可以像使用C++对象一样使用COM对象,这使得代码更加简洁,因为语言/编译器正在为您处理一些非常简单但繁琐的事情。

因此,不需要在C语言中执行以下操作(通过vtable并显式传递this参数):

pUnk->lpVtbl->SomeMethod(pUnk, 42);

你可以在C++中进行以下操作:
pUnk->SomeMethod(42);

您真的不想在每次进行COM调用时都要键入->lpVtbl,并确保传递正确的“this”参数(复制和粘贴时要小心!),对吗?

我的建议是找一本好的COM书籍 - Inside COM是一本好书 - 然后只需开始使用您熟悉的C ++子集。一旦您知道如何“原始”使用COM指针,并自己使用QI,AddRef等,则可以尝试使用帮助器库,这些库使用模板为您执行一些簿记工作。决定使用将COM错误映射到C ++异常的包装器有点更大的跳跃,因为您需要首先编写异常安全的C ++代码,因此需要了解这些问题的各种问题。但我想不出任何好的理由 - 除了纯粹的好奇心 - 再返回并使用纯C中的COM。


在编写 C 代码时需要写 pUnk->lpVtbl 的问题可以通过定义宏来轻松解决,例如 #define OBJ(x) ((x)->lpVtbl) 然后像这样使用 OBJ(pUnk)->SomeMethod(pUnk, 42)。由于 C 和 C++ 并不是严格的子集-超集关系,因此人们可以根据实际情况选择任何一种语言进行开发;后者并不会在每种情况下都自动替换前者,并且也不一定是线性和无可争议的改进。再加上某个著名厂商的 C/C++ 编译器甚至不支持全部的 C99,这一点更值得注意。 - Armen Michaeli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接