最近在做一个DataGrid链接DBF数据库的工程。DataGrid的数据是ADO Recordset。在操作DBF文件时常常出现ADO内部爆出的错误。这些错误有些很难调试。我们知道ADO是通过OLE DB操作数据库的。这些操作通常都会转化为对数据库的SQL语句。我们如果能知道最终的SQL语句是什么,就对调试有很大帮助。我链接数据库的Connect String 是:"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\;Extended Properties=DBASE 5.0"。
查找注册表后得到实现Provider的文件是:msjetoledb40.dll。用Depends工具查看这个文件发现只导出了通常COM都会导出3个接口。它的内部都有什么还是不知道。找到它的符号文件,msjetoledb40.pdb。随便用文本工具打开它,会发现依稀有OLE DB COM借口和函数的影子。用PDBDUMP工具把他的符号导出。这次看得清楚多了!很快找到这样一个符号:SetCommandText@CImpICommandText@@UAGJABU_GUID@@PBG@Z,显然CImpICommandText是实现ICommandText接口的类,如果编写过OLE DB Provider就会知道SetCommandText的第二个参数保存着那个神秘的SQL字符串。好想看看里面是什么!
接下来要在SetCommandText函数上设断点,这个断点可不好设。看到PDBDUMP的该函数输出上前面有<rva 0x62a0>,rva这不就是偏移地址嘛!赶快开动visual c++ debug程序。打开Moduals窗口,找到msjetoledb40.dll那一项,看看它的载入地址,然后再加上偏移。在这个最终地址上设立断点。运行程序,发现什么也没发生!!!Faint!!!看来那个rva是个冒牌的。没时间去研究PDBDUMP的源码了。只能另取它法。我们有符号,想找到它的内存地址。很简单嘛,突然想起WinDebug了。它有个命令:x 。就是完成这项工作的!只能先用WinDebug了。在WinDebug中打开程序。当msjetoledb.dll已经调入内存后,运行: x msjetoledb!*SetCommandText*。找到的一个就是ICommandText接口SetCommandText的地址。注意一定要把msjetoledb40.pdb装入才能找到呀!拿到这个地址,在VC中设端点,果然断掉了。成功了一半了!打开堆栈窗口,看看是谁调用SetCommandText,在call语句之前,肯定有push 语句,这个函数有两个参数,其中第一个push就是SQL字符串的地址。 突然发现堆栈是错误的。那就打开内存窗口,察看esp,esp指向的值,在断掉的那一刻指向是返回地址,加4是ICommandText实现类的地址,再加4是第一个参数,再加4就是Sql字符串的地址,察看地址的内容,My GOD!他终于出来了!
试验了一下。当我在DataGrid中修改值后,断点会马上激活,字符串显示果然就是ADO参考书上的“Update "语句。