标题: 用C语言调用COM组件
作者: Demon
链接: https://demon.tw/programming/invoke-com-in-pure-c.html
版权: 本博客的所有文章,都遵守“署名-非商业性使用-相同方式共享 2.5 中国大陆”协议条款。
在这个C++大行其道的年代,想用纯C语言实现某些功能是如此的困难,相关的资料非常的难找。为此加了一个QQ群,看看有没有高手知道怎样用纯C语言调用COM组件。没想到马上被一句话顶了回来:“你为什么要这么做?用C++不就行了。”让我想到《Assembly Language Step-by-Step: Programming with Linux》中的介绍。作者是一个Turbo Pascal迷,他想知道怎样在Turbo Pascal程序中使用windows系统提供的新接口(即API),于是向一个高手请教,高手却尖锐的反问他:"Why would you want to do that?That’s what C’s for."作者最后说,当一个人问你“你为什么要这么做”的时候,他真实的意思是“你问的问题用我擅长的工具无法做到或者完全超出了我的经验范围,但是我又不想丢脸地去承认,所以……”你可以马上回答他:“因为我想知道这怎样实现。”
我当然知道用C++可以很轻松的调用COM,我只是想知道用C语言如何实现。高手发话了:“C比C++麻烦太多,而且能用C的场合都能用C++,还有必要用C吗?”不会就直接说,何必大谈C++有多么好。不可否认C++确实很强大,但是我看不惯用C++的人这种不可一世的优越感,厌屋及乌,也很反感C++。
废话说多了,用C调用COM最大的问题是如何获得头文件和相关定义。其实微软提供了相关的工具,有了VC中midl.exe和OLE View.exe这两个工具,用纯C语言调用COM组件也是一件很简单的事。下面就解释一下如何使用这两个工具得到ADO组件(一个与数据库有关的COM组件)的头文件和相关CLSID/IID的定义文件。
先运行OLE VIEW,用它打开msado15.dll文件,然后可以选择文件->另存为,可以保存得到msado15.idl,接下来用命令
midl /h msado15.h msado15.idl
得到msado15.h和msado15_i.c文件,它们可以用于开发。
输入命令后可能会得到一大堆的警告和错误信息,我得到了如
下几种:
error MIDL2025:syntax error:expecting a type specification near "ADO_LONGPTR"
该信息表示ADO_LONGPTR前后应该有一个类型描述符,但实际上ADO_LONGPTR本身就是一个类型描述符,这表明midl.exe可能也遵循C语言“先定义后使用”的规则,查看msado15.idl文件,发现确实AD_LONGPTR的定义点出现在报错点之前,调整顺序后错误消失。
error MIDL2272:(async) interface must derive from another (async) interface
经过分析msado15.idl的结构,发现一个规律,即出现该报错的点都是接口之间存在三层及以上的层次性,如A–>B–>C,即A继承自B,B又继承自C,而它们在msado15.idl中的出现顺序是A B C,这样一来,当midl.exe在看到A的定义后,发现A是继承自B的,于是期待B是一个从已知接口导出的接口,可是读到B时发现B是从C导出的,且此时C仍是未知接口(因为其定义出现在B之后),于是宣布“B必须能从另一个接口导出”换句话说:midl.exe只支持两层推导,即如果只有A–>B,它们的顺序可以是A B或B A,都不会错,但如果超过两层,是A–>B–>C,则顺序必须是C B A,根据这个规则调整文件中接口出现的顺序,错误消失。
还有一些警告信息,因为只是警告,所以没做分析,简单的加上一个/no_warn选项,眼不见为净。
现在你可以得到开发所需的msado15.h和msado15_i.c两个文件。分析msado15.h后发现,如果定义了CINTERFACE这个定义值,则会生成接口的C风格定义;如果定义COBJMACROS,则会为每个接口的方法定义一组函数调用宏。
参考链接:Inside COM — ADO with pure C
赞赏微信赞赏支付宝赞赏
随机文章:
调用COM和调用OCX是一样的吧
哥们 严重同意 我就是不用C++ 就是用C 就是用C实现一切
这个文章对我太有帮助了,我也是喜欢C