用C语言调用COM组件

标签: , ,

在这个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

随机文章:

  1. Windows下用TCC编译Lua源码
  2. C语言标准库函数rand与多线程
  3. JavaScript 记忆(Memoization)
  4. 用C语言实现PHP的urlencode函数
  5. Python,又见Python

3 条评论 发表在“用C语言调用COM组件”上

  1. JJYYXXOO说道:

    调用COM和调用OCX是一样的吧

  2. zisboss说道:

    哥们 严重同意 我就是不用C++ 就是用C 就是用C实现一切

  3. 飞飞说道:

    这个文章对我太有帮助了,我也是喜欢C

留下回复