从C到Delphi的接口声明转换(2分)

  • 主题发起人 主题发起人 Oldtiger
  • 开始时间 开始时间
O

Oldtiger

Unregistered / Unconfirmed
GUEST, unregistred user!
虽然Delphi作为一种极其优秀的开发工具已经被越来越多的开发人员选用,但是它毕竟面世时间不算太长,加上有的软件开发厂商实力不强或是其他原因,造成部分二次开发平台仅仅提供C语言的开发接口。
但这并不是说用Delphi就不能完成这些工作.我们知道,软件厂商提供开发包实际基本上都是以动态连接库的方式实现的,他们将可以调用的函数、过程包括一些特定数据格式组合起来, 作为一个开发包,通过c编译器形成一个可重用的DLL文件,而所谓的开发接口往往就是动态连接库(.dll)的声明文件,他们即使提供Delphi下的接口,也就是用Pascal写一遍对这些动态库的声明。如果我们自己作这个翻译工作,就不存在厂商是否提供Delphi下接口的问题了。换言之,对于以DLL方式出现的开发包,只要有c的文件头,理论上都可以在Delphi下照样开发。
经过对比,我们发现c语言中存在的所有数据类型在Delphi的Object Pascal中都有对应类型存在;同时c语言调用动态库的4种方式在Delphi编译器中也都覆盖了,这就保证了我们的工作是可行的,如果你对此尚有疑问,那么可以看看WinProcs和ShellAPI两个单元。这两个单元就是Inprise写的对Windows系统函数(也是C语言开发,存在于DLL文件中的)的声明调用。
这里我们就来看看写这个声明文件需要注意的一些问题。在delphi中有两种声明方式:implicit (静态的) 和 explicit (动态的)。
对于implicit方式要求程序运行时动态库一定要存在,否则程序不能运行.而explicit方式可以没有动态库存在.例如一个界面程序,如果3维显示是在一个dll中实现的,那么我们如果采用explicit方式调用就可以做到如果动态库存在就用3维显示,否则用2维显示。
采用explicit方式的另一个好处是可以加快程序的启动速度.因为explicit方式让程序在执行到调用语句时才装载dll文件.但同时implicit方式比较简单,所以用的也更多。
  implicit方式的典型声明格式是:
  procedure Foo(X: Integer);
external 'BAR' index 1;
  这里再次提醒:如果程序找不到对应的dll文件,在编译和运行时都会出现错误。
  Explicit方式就麻烦一些了.实际上这种方式在vb中用的更多一些.如果你的确希望这样做,那么可以参考下面的代码:
   var Hbar: Thandle;
   Foo: procedure (X: Integer);
{$IFDEF WIN32} stdcall;
{$ENDIF}
   begin
   Hbar := LoadLibrary('BAR.DLL');
   if Hbar 〉= 32 then
{ success } begin
   Foo := GetProcAddress(HBar, 'FOO');
  ...
   Foo(1);
...
   FreeLibrary(HBar);
   end
   else
MessageDlg('警告: 没有发现 BAR.DLL', mtError, [mbOk], 0)
   end.
请注意一下, 这段代码编译时是不会出现错误的,在运行时也会按照程序指定步骤完成.DLL的调入时间也如我们前面提及的,是在需要时才引入的。
在c语言中常常采用IMPLIB和IMPDEF两个工具生成.h文件,这个文件就是开发包中我们见到的头文件了.我们需要作的工作就是将这个文件准确地翻译成pascal格式,而且可以被编译器准确的用来编译成dll的声明文件。
为了更好的说明问题,我们不妨先看看一个简化的c语言的头文件:
  /**********/ *
  * wing.h - WinG functions, types, and definitions *
  * Copyright (c) 1994 Microsoft Corp. All rights reserved. *
  /*********/
  #ifndef _INC_WING
  #define _INC_WING
  #ifndef _INC_WINDOWS
  #include /* Include windows.h if not already included */
  #endif
  #ifdef __cplusplus
  extern "C" { /* Assume C declarations for C++ */
  #endif
  #if defined(WIN32) || defined(_WIN32)
  #define WINGAPI WINAPI #else
  #define WINGAPI WINAPI _loadds
  #endif
  /***** WingDC and WinGBitmap ********/
  HDC WINGAPI WinGCreateDC( void );
  BOOL WINGAPI WinGRecommendDIBFormat( BITMAPINFO FAR *pFormat );
  HBITMAP WINGAPI WinGCreateBitmap( HDC WinGDC, BITMAPINFO const FAR *pHeader,void FAR *FAR *ppBits )
  void FAR *WINGAPI WinGGetDIBPointer( HBITMAP WinGBitmap,BITMAPINFO FAR *pHeader );
  UINT WINGAPI WinGGetDIBColorTable( HDC WinGDC, UINT StartIndex,UINT NumberOfEntries, RGBQUAD FAR *pColors );
  UINT WINGAPI WinGSetDIBColorTable( HDC WinGDC, UINT StartIndex,
  UINT NumberOfEntries, RGBQUAD const FAR *pColors );
  /***** Halftoning **********/
  HPALETTE WINGAPI WinGCreateHalftonePalette( void );
  typedef enum WING_DITHER_TYPE
  { WING_DISPERSED_4x4,WING_DISPERSED_8x8,WING_CLUSTERED_4x4} WING_DITHER_TYPE;
  HBRUSH WINGAPI WinGCreateHalftoneBrush( HDC Context, COLORREF crColor,WING_DITHER_TYPE DitherType );
  /***** Blts **********/
  BOOL WINGAPI WinGBitBlt( HDC hdcDest, int nXOriginDest,int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc,int nXOriginSrc, int nYOriginSrc );
  BOOL WINGAPI WinGStretchBlt( HDC hdcDest, int nXOriginDest,int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc,int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc );
  #ifdef __cplusplus
  } /* End of extern "C" */
  #endif
  #endif // _INC_WING
从中我们可以归纳出需要翻译的三部分内容:编译开关,数据结构,函数调用。为了便于大家完成翻译工作,我摘抄了一张c语言和pascal语言的数据类型对照表,可以供大家参考:
C/C++ Type
Object Pascal Type
C/C++ Type
Object Pascal Type

unsigned short [int]
word
char
char

[signed] short [int]
smallint
signed char
shortint

unsigned [int]
cardinal { 3.25 fix }
unsigned char
byte

[signed] int
integer
char*
pchar

uint
longint { or cardinal }
lpstr or pstr
pchar

word
word
lpwstr or pwstr
pwidechar { 3.12 fix }

dword
longint { or cardinal }
void*
pointer

unsigned long
longint { or cardinal }
bool
bool

unsigned long int
longint { or cardinal }
float
single

[signed] long
longint
do
uble
do
uble

[signed] long int
longint
   
  下面是一些常用和常见数据结构的对照表:
C/C++ Type
Object Pascal Type
C/C++ Type
Object Pascal Type

handle
thandle
debughookinfo
tdebughookinfo

farproc
tfarproc
bitmapcoreheader
tbitmapcoreheader

atom
tatom
bitmapinfoheader
tbitmapinfoheader

tpoint
tpoint
bitmapinfo
tbitmapinfo

trect
trect
bitmapcoreinfo
tbitmapcoreinfo

colorref
tcolorref
bitmapfileheader
tbitmapfileheader

ofstruct
tofstruct
ttpolygonheader
tpolygonheader

handletable
thandletable
rasterizer_status
trasterizer_status

bitmap
tbitmap
mousehookstruct
tmousehookstruct

rgbtriple
trgbtriple
cbtactivatestruct
tcbtactivatestruct

rgbquad
trgbquad
hardwarehookstruct
thardwarehookstruct

metarecord
tmetarecord
eventmsg
teventmsg

metaheader
tmetaheader
pattern
tpattern { tlogbrush }

metafilepict
tmetafilepict
newtextmetric
tnewtextmetric

textmetric
ttextmetric
paletteentry
tpaletteentry

logbrush
tlogbrush
logpalette
tlogpalette

logpen
tlogpen
kerningpair
tkerningpair

logfont
tlogfont
outlinetextmetric
toutlinetextmetric

enumlogfont
tenumlogfont
glyphmetrics
tglyphmetrics

panose
tpanose
pointfx
tpointfx

fixed
tfixed
ttpolycurve
tttpolycurve

mat2
tmat2
minmaxinfo
tminmaxinfo

abc
tabc
paintstruct
tpaintstruct

wndclass
twndclass
createstruct
tcreatestruct

msg
tmsg
cbt_createwnd
tcbt_createwnd

seginfo
tseginfo
measureitemstruct
tmeasureitemstruct

accel
taccel
drawitemstruct
tdrawitemstruct

size
tsize
deleteitemstruct
tdeleteitemstruct

dcb
tdcb
compareitemstruct
tcompareitemstruct

comstat
tcomstat
windowpos
twindowpos

helpwininfo
thelpwininfo
windowplacement
twindowplacement

ctlstyle
tctlstyle
nccalcsize_params
tnccalcsize_params

ctltype
tctltype
menuitemtemplateheader
tmenuitemtemplateheader

ctlinfo
tctlinfo
menuitemtemplate
tmenuitemtemplate

ddeadvise
tddeadvise
mdicreatestruct
tmdicreatestruct

ddedata
tddedata
clientcreatestruct
tclientcreatestruct

ddepoke
tddepoke
multikeyhelp
tmultikeyhelp

ddeaack
tddeack
kanjistruct
tkanjistruct

devmode
tdevmode
   
以上仅仅是常用的一部分,更多的结构转换可以参见WINDOWS.H头文件和WINDOWS.pas,将两者作一个对比可以学习到许多技巧。
在上面的c语言文件头中您应该可以按照上表作出转换了。可能存在的问题是一个数据结构的变换:
   typedef enum WING_DITHER_TYPE
   {WING_DISPERSED_4x4,WING_DISPERSED_8x8,WING_CLUSTERED_4x4} WING_DITHER_TYPE;
  这是一个枚举结构,我们可以翻译成这样:
   Type WING_DITHER_TYPE =(WING_DISPERSED_4x4,WING_DISPERSED_8x8,WING_CLUSTERED_4x4);
  我们再来看看函数和过程的转换吧:
  WinGCreateDC function:
  HDC WINGAPI WinGCreateDC( void );
  显然这是一个没有返回值的函数,而且没有入口参数,我们可以将其转换成:
  function WinGCreateDC: HDC;
{$IFDEF WIN32} stdcall;
{$ENDIF} external 'WING' index 1001;
这里的index 1001是从IMPDEF的.DEF 文件中得到的,一些反编译和调试工具也可以得到其值.但是我们推荐采用按照名称方式访问,这样可以适合于更多的场合。
  按照同样的方式,我们再来翻译几个函数:
  function WinGRecommendDIBFormat(pFormat: PBitmapInfo): Bool;
{$IFDEF WIN32} stdcall;
{$ENDIF} external 'WING' index 1002;
  function WinGCreateBitmap(WinGDC: HDC;Const pHeader: PBitmapInfo;ppBits: PPointer): HBITMAP;
{$IFDEF WIN32} stdcall;
{$ENDIF} external 'WING' index 1003;
  function WinGCreateHalftoneBrush(Context: HDC;crColor: TColorRef;DitherType: WING_DITHER_TYPE): HBRUSH;
{$IFDEF WIN32} stdcall;
{$ENDIF} external 'WING' index 1008;
这些都是按照静态方式声明的。
编译器指令的翻译是相对比较麻烦的事情.而且要考虑到32位代码和16位代码的兼容性.一般我们采用{$IFDEF WIN32}{$ENDIF}这种方式处理这个问题.
最后我们推荐一个很好的代码自动转换辅助工具headConv.这是著名的荷兰程序员Bob的杰作.最初的版本(1.0,2.0)是要收费的(25美金),我们得到了其最新的一个免费版本3.25命令行版,你可以从一个delphi控件收集站点(delphi根据地 http://warez.zb169.net/)去下载它.其用法也非常简单,一共有三个可选项:
  -o 覆盖原有单元
  -x 强制产生动态声明单元;
  -m 强制产生静态声明单元;
这样就可以大大减少手工翻译的时间,而将主要精力用于润色和优化。
 
怎么长,我头疼。
 
接受答案了.
 
后退
顶部