个人用的少的东西,笔记之,以作记录

实际上老久之前,应该在Delphi中就可以链接使用Obj文件了吧,我用的第一个Delphi版本是D7,我记得他就可以了。至于再往前追述,就不晓得初始来源是哪个版本了。不过对于以前的版本的链接obj只能是OMF这个格式,这个格式是很早很早之前定义的一个文件格式,之后微软都转向了COFF这种格式了,也就是说VC编译出来的OBJ文件都是COFF格式。所以,以前要在Delphi中使用obj就要多走几步路程,要么使用VC编译的obj是COFF格式的,此时要使用COFF2OMF来进行转换,将COFF转换成OMF格式的,要么就是拿到C的源码,使用BCB等工具来编译以生成OMF的格式的obj。然后才能在Delphi中使用{$Link指令进行链接而使用里面的函数。

今天早上,俺在群中偶然听到了Delphi XE2可以支持COFF的obj静态链接了。这也就是说,可以直接使用VC编译生成的Obj文件了。之后写了一个测试的Demo,很简单的函数

#include "stdafx.h"

extern "C" {
extern int add(int x,int y);
}

int add(int x,int y)
{
return x+y;
}

编译生成了obj文件之后给Delphi使用,刚开始没改编译模式,生成的是Debug版本的obj文件,在Delphi中使用的时候,总是会报错误,无法发现add的前置引用,折腾了半天,也没搞好,之后编译成Release版本,在给Delphi使用,则运行成功!不知道是我搞的有问题还是说只能是Release版本可用,总之,发布Release的Obj给Delphi使用是没问题的。

不过这个例子就比较过于简单了,没实际作用,如果真实在开发过程中,那复杂度肯定是天差地别,于是找了一个VC版的Hook库,相对来说,这个库的代码就比较多一些了,而且也引用了好些系统API,比较复合实际开发的目的。我找的这个Hook库是海风月影大大的库,可以从这里下载,编译生成Obj文件之后,拿到Delphi中使用,编译就报了未声名

__imp__LoadLibraryA@4这样的错误,可见,这系统API在Obj中使用的,还不是真的将API函数的地址放入了,只是一个动态的预指定,于是编译的时候就找不到对应的函数了,所以我们需要在链接Obj的时候将这些导入函数在我们的程序中声名,比较蛋疼的是Delphi中的@是关键字,所以这个在VC的函数中,我们就需要将函数全部声名为C版本的函数导出和导入,C版本的会在函数名称前加入一个下划线,同时将WinApi的那套系统函数都在VC中写一个外置函数声名,API函数名字全部换掉,比如原来里面调用的是LoadLibrary这个是在Windows.h中声名的,我们现在不用这个,换一个声名

extern HMODULE __cdecl LoadLibraryExEx(LPCSTR lpLibFileName);

声名一个外部导入函数LoadLibraryExEx,然后将LoadLibrary都改成LoadLibraryExEx,同样道理,将API函数都做对应的处理之后编译

然后在Delphi中再将这些函数作为这个obj的导入函数,

function _LoadLibraryExEx(lpLibFileName: PAnsiChar): HMODULE;cdecl;
begin
Result := LoadLibraryA(lpLibFileName);
end;

这样包装一下,在进入链接Obj的时候,就会找到对应的函数了,搞定之后,还会发现,会报free的这个函数的错误,这个是VC的一个函数,函数在MSVCR70.DLL这个库中,所以也需要包装一下

extern void __cdecl free(void *);

malloc这个函数一样,之后在Delphi中,需要引用到MSVCR70.DLL这个动态库

procedure free(p: Pointer);cdecl;external 'MSVCR70.DLL';

procedure _free(p: Pointer);cdecl;
begin
free(p);
end;

这样就OK了,编译程序,在用通过

至于为何我要将VC中动态库的WINAPI都换成__cdecl的声名模式,可以自己去试一试,看看效果了!主要还是我前面说的Delphi中的@是一个关键字!

当然,这个Free和malloc也可以不用他这个Dll中的函数,可以直接用Delphi的也可以

比如

function _malloc(size_t: DWORD): Pointer;cdecl;
begin
GetMem(Result,Size_t);
end;

procedure _free(p: Pointer);cdecl;
begin
FreeMem(p);
end;

这样就免去了外部DLL的东西了!

×××