




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
20/20目录Delphi指针与C指针区别 2一、类型指针的定义。 2二、无类型指针的定义。 2三、指针的解除引用。 2四、取地址(指针赋值)。 3五、指针运算。 3六、动态内存分配。 3七、字符数组的运算。 4八、函数指针。 4九.数据类型对照表 5十.关键字对照表 6如何将C/C++程序转译成Delphi 81c头文件分解 82基本转换 82.1名字 82.2单元附属 82.3#defines和constants 93数据类型 93.1基本数据类型 93.2winapi公共类型 103.3数组 113.4字符串 113.5枚举类型: 113.6结构、记录 124.宏命令 155条件句 166函数 166.1基本的 166.2调用约定 167.连接 177.1静态链接 177.2动态链接 188公共支持单元 20
Delphi指针与C指针区别大家都认为,C语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上。因此,说指针是C语言的灵魂,一点都不为过。同时,这种说法也让很多人产生误解,似乎只有C语言的指针才能算指针。Basic不支持指针,在此不论。其实,Pascal语言本身也是支持指针的。从最初的Pascal发展至今的ObjectPascal,可以说在指针运用上,丝毫不会逊色于C语言的指针。以下内容分为八个部分,分别是一、类型指针的定义二、无类型指针的定义三、指针的解除引用四、取地址(指针赋值)五、指针运算六、动态内存分配七、字符数组的运算八、函数指针九、数据类型对照表十、关键字对照表一、类型指针的定义。对于指向特定类型的指针,在C中是这样定义的:int*ptr;char*ptr;与之等价的ObjectPascal是如何定义的呢?varptr:^Integer;ptr:^char;其实也就是符号的差别而已。二、无类型指针的定义。C中有void*类型,也就是可以指向任何类型数据的指针。ObjectPascal为其定义了一个专门的类型:Pointer。于是,ptr:Pointer;就与C中的void*ptr;等价了。三、指针的解除引用。要解除指针引用(即取出指针所指区域的值),C的语法是(*ptr),ObjectPascal则是ptr^。四、取地址(指针赋值)。取某对象的地址并将其赋值给指针变量,C的语法是ptr=&Object;ObjectPascal则是ptr:=@Object;也只是符号的差别而已。五、指针运算。在C中,可以对指针进行移动的运算,如:chara[20];char*ptr=a;ptr++;ptr+=2;当执行ptr++;时,编译器会产生让ptr前进sizeof(char)步长的代码,之后,ptr将指向a[1]。ptr+=2;这句使得ptr前进两个sizeof(char)大小的步长。同样,我们来看一下ObjectPascal中如何实现:vara:array[1..20]ofChar;ptr:PChar;//PChar可以看作^Charbeginptr:=@a;Inc(ptr);//这句等价于C的ptr++;Inc(ptr,2);//这句等价于C的ptr+=2;end;六、动态内存分配。C中,使用malloc()库函数分配内存,free()函数释放内存。如这样的代码:int*ptr,*ptr2;inti;ptr=(int*)malloc(sizeof(int)*20);ptr2=ptr;for(i=0;i<20;i++){*ptr=i;ptr++;}free(ptr2);ObjectPascal中,动态分配内存的函数是GetMem(),与之对应的释放函数为FreeMem()(传统Pascal中获取内存的函数是New()和Dispose(),但New()只能获得对象的单个实体的内存大小,无法取得连续的存放多个对象的内存块)。因此,与上面那段C的代码等价的ObjectPascal的代码为:varptr,ptr2:^integer;i:integer;beginGetMem(ptr,sizeof(integer)*20);//这句等价于C的ptr=(int*)malloc(sizeof(int)*20);ptr2:=ptr;//保留原始指针位置fori:=0to19dobeginptr^:=i;Inc(ptr);end;FreeMem(ptr2);end;对于以上这个例子(无论是C版本的,还是ObjectPascal版本的),都要注意一个问题,就是分配内存的单位是字节(BYTE),因此在使用GetMem时,其第二个参数如果想当然的写成20,那么就会出问题了(内存访问越界)。因为GetMem(ptr,20);实际只分配了20个字节的内存空间,而一个整形的大小是四个字节,那么访问第五个之后的所有元素都是非法的了(对于malloc()的参数同样)。七、字符数组的运算。C语言中,是没有字符串类型的,因此,字符串都是用字符数组来实现,于是也有一套str打头的库函数以进行字符数组的运算,如以下代码:charstr[15];char*pstr;strcpy(str,"teststr");strcat(str,"_testok");pstr=(char*)malloc(sizeof(char)*15);strcpy(pstr,str);printf(pstr);free(pstr);而在ObjectPascal中,有了String类型,因此可以很方便的对字符串进行各种运算。但是,有时我们的Pascal代码需要与C的代码交互(比如:用ObjectPascal的代码调用C写的DLL或者用ObjectPascal写的DLL准备允许用C写客户端的代码)的话,就不能使用String类型了,而必须使用两种语言通用的字符数组。其实,ObjectPascal提供了完全相似C的一整套字符数组的运算函数,以上那段代码的ObjectPascal版本是这样的:varstr:array[1..15]ofchar;pstr:PChar;//Pchar也就是^CharbeginStrCopy(@str,'teststr');//在C中,数组的名称可以直接作为数组首地址指针来用//但Pascal不是这样的,因此str前要加上取地址的运算符StrCat(@str,'_testok');GetMem(pstr,sizeof(char)*15);StrCopy(pstr,@str);Write(pstr);FreeMem(pstr);end;八、函数指针。在动态调用DLL中的函数时,就会用到函数指针。假设用C写的一段代码如下:typedefint(*PVFN)(int);//定义函数指针类型intmain(){HMODULEhModule=LoadLibrary("test.dll");PVFNpvfn=NULL;pvfn=(PVFN)GetProcAddress(hModule,"Function1");pvfn(2);FreeLibrary(hModule);}就我个人感觉来说,C语言中定义函数指针类型的typedef代码的语法有些晦涩,而同样的代码在ObjectPascal中却非常易懂:typePVFN=Function(para:Integer):Integer;varfn:PVFN;//也可以直接在此处定义,如:fn:function(para:Integer):Integer;hm:HMODULE;beginhm:=LoadLibrary('test.dll');fn:=GetProcAddress(hm,'Function1');fn(2);FreeLibrary(hm);end;Delphi构造函数中抛出异常会自动先调用析构函数Delphi里,如果构造函数中抛出了异常,则会自动先执行析构函数,然后再把异常向外抛出;而在C里,构造函数中若有异常抛出,则析构函数是不会被调用的。Delphi简化了COM接口中的AddRef、Release和QueryInterfaceC里一般用模板对COM接口进行封装,而在Delphi里,AddRef、Release以及QueryInterface都被编译器隐藏掉了,当把一个IUnknown类型的变量(本质上也是一个指针)赋值给另一个变量时,编译器在背后自动AddRef,当一个IUnknown变量离开作用域的时候(再也没有人使用它),Release被自动调用,而QueryInterface被抽象为AS运算符:软件开发网procedureFoo(constAParam:IUnknown);varbar:IUnknown;other:IStream;beginbar:=AParam;//AParam指向的实例由于赋值操作被AddRef一次other:=barasIStream;//调用了一次QueryInterface,引用计数再次加一end;//返回时,other和bar都离开作用域,分别被调用Release各一次C中用模板(比如_com_ptr)也可以使引用计数自动化,不过QueryInterface就没那么方便了。九.数据类型对照表序号C/C++类型ObjectPascal类型序号C/C++类型ObjectPascal类型1unsignedshort[int]Word12charChar2[signed]short[int]SmallInt13signedcharShortInt3unsigned[int]Cardinal
{3.25fix}14unsignedcharByte4[signed]intInteger15char*PChar5UINTLongInt
{orCardinal}16LPSTR
orPSTRPChar6WORDWord17LPWSTR
orPWSTRPWideChar
{3.12fix}7DWORDLongInt
{orCardinal}18void*Pointer8unsignedlongLongInt
{orCardinal}19BOOLBool9unsignedlongintLongInt
{orCardinal}20floatSingle10[signed]longLongInt21doubleDouble11[signed]longintLongInt22longdoubleExtended十.关键字对照表LP,NP,PP,P前缀:iffirst=TthenTbecomesPelseP前缀x序号C/C++类型ObjectPascal类型序号C/C++类型ObjectPascal类型1HANDLETHandle39ABCTABC2FARPROCTFarProc40RASTERIZER_STATUSTRasterizer_Status3ATOMTAtom41MOUSEHOOKSTRUCTTMouseHookStruct4TPOINTTPoint42CBTACTIVATESTRUCTTCBTActivateStruct5TRECTTRect43HARDWAREHOOKSTRUCTTHardwareHookStruct6COLORREFTColorRef44EVENTMSGTEventMsg7OFSTRUCTTOFStruct45WNDCLASSTWndClass8DEBUGHOOKINFOTDebugHookInfo46MSGTMsg9BITMAPTBitMap47MINMAXINFOTMinMaxInfo10RGBTRIPLETRGBTriple48SEGINFOTSegInfo11RGBQUADTRGBQuad49ACCELTAccel12BITMAPCOREHEADERTBitmapCoreHeader50PAINTSTRUCTTPaintStruct13BITMAPINFOHEADERTBitmapInfoHeader51CREATESTRUCTTCreateStruct14BITMAPINFOTBitmapInfo52CBT_CREATEWNDTCBT_CreateWnd15BITMAPCOREINFOTBitmapCoreInfo53MEASUREITEMSTRUCTTMeasureItemStruct16BITMAPFILEHEADERTBitmapFileHeader54DRAWITEMSTRUCTTDrawItemStruct17HANDLETABLETHandleTable55DELETEITEMSTRUCTTDeleteItemStruct18METARECORDTMetaRecord56COMPAREITEMSTRUCTTCompareItemStruct19METAHEADERTMetaHeader57WINDOWPOSTWindowPos20METAFILEPICTTMetaFilePict58WINDOWPLACEMENTTWindowPlacement21TEXTMETRICTTextMetric59NCCALCSIZE_PARAMSTNCCalcSize_Params22NEWTEXTMETRICTNewTextMetric60SIZETSize23LOGBRUSHTLogBrush61MENUITEMTEMPLATEHEADERTMenuItemTemplateHeader24LOGPENTLogPen62MENUITEMTEMPLATETMenuItemTemplate25PATTERNTPattern{TLogBrush}63DCBTDCB26PALETTEENTRYTPaletteEntry64COMSTATTComStat27LOGPALETTETLogPalette65MDICREATESTRUCTTMDICreateStruct28LOGFONTTLogFont66CLIENTCREATESTRUCTTClientCreateStruct29ENUMLOGFONTTEnumLogFont67MULTIKEYHELPTMultiKeyHelp30PANOSETPanose68HELPWININFOTHelpWinInfo31KERNINGPAIRTKerningPair69CTLSTYLETCtlStyle32OUTLINETEXTMETRICTOutlineTextMetric70CTLtypeTCtltype33FIXEDTFixed71CTLINFOTCtlInfo34MAT2TMat272DDEADVISETDDEAdvise35GLYPHMETRICSTGlyphMetrics73DDEDATATDDEData36POINTFXTPointFX74DDEPOKETDDEPoke37TTPOLYCURVETTTPolyCurve75DDEAACKTDDEAck38TTPOLYGONHEADERTPolygonHeader76DEVMODETDevMode77KANJISTRUCTTKanjiStruct
如何将C/C++程序转译成Delphi1c头文件分解2基本转换2.1名字该c-程序通常用大写字母类型标识符,例如MY_TYPE。在Delphi中,类型标识符是有T开头加上类型名称组成,不使用下划线。C类型标识符MY_TYPE的Delphi类型是TMyType。在C早期的头文件的指针类型为LPMY_TYPE。翻译成Delphi应该是PMyType才符合Borland的风格。常量的命名通常与原来的名称,包括大写字母和下划线。以下是一些实例CDelphi-翻译typedefstruct_IMAGE_FILE_HEADER{
WORDMachine;
WORDNumberOfSections;
DWORDTimeDateStamp;
DWORDPointerToSymbolTable;
DWORDNumberOfSymbols;
WORDSizeOfOptionalHeader;
WORDCharacteristics;
}
IMAGE_FILE_HEADER,
*PIMAGE_FILE_HEADER;type
PImageFileHeader
=^TImageFileHeader;
TImageFileHeader
=packedrecord
Machine:Word;
NumberOfSections:Word;
TimeDateStamp:DWORD;
PointerToSymbolTable:DWORD;
NumberOfSymbols:DWORD;
SizeOfOptionalHeader:Word;
Characteristics:Word;
end;
#defineLANG_NEUTRAL0x00
#defineLANG_AFRIKAANS0x36
#defineLANG_ALBANIAN0x1C
#defineLANG_ARABIC0x01
#defineLANG_BASQUE0x2D
#defineLANG_BELARUSIAN0x23
#defineLANG_BULGARIAN0x02
#defineLANG_CATALAN0x03
#defineLANG_CHINESE0x04CONST
LANG_NEUTRAL=$00;
LANG_AFRIKAANS=$36;
LANG_ALBANIAN=$1C;
LANG_ARABIC=$01;
LANG_BASQUE=$2D;
LANG_BELARUSIAN=$23;
LANG_BULGARIAN=$02;
LANG_CATALAN=$03;
LANG_CHINESE=$04;2.2单元附属C和C++使用#include在另一头文件和源文件包含头文件。Delphi是引用单元(在USES中引用)代替头文件。例如:D3D.HincludesD3DTYPES.H,D3DCAPS.HD3DTYPES.HincludesDDRAW.H一个单元包含一个头文件的翻译,所以D3DTYPES.H和D3DCAPS.H被请求并入D3D.H因此翻译成delphi,则是D3D.PASUSES需要D3DTYPES.PAS,D3DCAPS.PAS。在windows.pasBorland已经为我们做了很多工作。Borland的Windows单元包含了大部分的基本的Windows的数据类型,所以任何翻译单元需要Windows数据类型需要在其USES中引用Windows单元。注意:在Delphi1,为windows.pas替代winprocs.pas和wintypes.pas,因为这两个单元包括在windows.pas的Delphi32位版本定义的Delphi16位。
在Delphi2中,为了向后兼容,这两个文件在Delphi的32位版本中也被当作windows.pas。
一些头文件包含源码不被直接翻译成Pascal语言,但头文件在汇编上的影响必须纳入翻译代码。例如,PSHPACK.H包含编译器指令,不能直接翻译到Delphi;PSHPACK4.H指示编译器使用4字节的包。2.3#defines和constantsC语言中#define被用于:声明一个常量;声明一个条件编译的符号;声明一个宏;C语言中常量的声明如下:#defineNameOfConstantValue例如:#defineTIME_ZONE_ID_UNKNOWN0#defineTIME_ZONE_ID_STANDARD1#defineTIME_ZONE_ID_DAYLIGHT2翻译成delphi:CONSTTIME_ZONE_ID_UNKNOWN=0;TIME_ZONE_ID_STANDARD=1;TIME_ZONE_ID_DAYLIGHT=2;2.3.116进制的值C语言#defineMY_CONSTANT0xFFDelphi语言:CONSTMY_CONSTANT=$FF;3数据类型3.1基本数据类型CDelphiUNSIGNEDLONGDword(Longint)UNSIGNEDSHORTwordINTintegerUNSIGNEDCHARbyte,char(Dependingonusage)3.2winapi公共类型WindowsAPI定义了一些常见API类型。这是建议的名称,翻译尽可能使用。windows.pas声明了许多这些类型,其中一些如下:APIType声明在DELPHI中用法Type说明ULONGULongDWordPULONGPULong^DWordUSHORTUShortSmallIntPUSHORTPUShort^SmallIntUCHARUCharBytePUCHARPUChar^ByteDWORDDWordDWordPDWORD,LPDWORDPDWord^DWordBOOLBoolBoolPBOOL,LPBOOLPBool^BoolBYTEByteBytePBYTE,LPBYTEPByte^ByteWORDWordWordPWORD,LPWORDPword^WordINTIntegerIntegerPINT,LPINTPInteger^IntegerLPVOIDPointerUntypedPointerUINTUIntIntegerPUINT,LPUINTPUInt^IntegerWCHARWCharWideCharPWCHAR,LPWCHAR,PCWCH,LPCWCH,NWPSTR,PWChar^WideCharPWSTR,LPWSTRLPWStr^WideCharPCWSTR,LPCWSTRLPCWStr^WideCharPCH,LPCHPChar^CharPSTR,LPSTRLPStr^CharPCSTR,LPCSTRLPCStr^CharHANDLETHandleDWordPHANDLE,LPHANDLEPHandle^DWord3.3数组方法1C语言中的数组:DWORDMyType[4]翻译成DELPHI如下:MyType=Array[0..3]ofDWord;方法2:其它:#defineNumberOfElements5//...typedefstruct_MyRec{DWORDMyArray[NumberOfElements]}MyRec,*PMyRec翻译成delphiConstNumberOfElements=5//...TypeTmyArray=RecordMyArray:Array[0..NumberOfElements-1]ofDWord;end;3.4字符串c中的字符串:在C语言中,字符串是char类型的数组。通常,一个字符串的声明中使用常数声明指定的最大字符串长度,如下面的示例所示:#defineRAS_MaxEntryName256#defineRASENTRYNAMEAstructtagRASENTRYNAMEARASENTRYNAMEA{DWorddwSize;CHARszEntryName[RAS_MaxEntryName+1];};第一行声明一个RAS_MaxEntryName常数为256,指定字符串的最大长度值。在后面声明一个结构体,包含一个null结尾的字符串:CHARszEntryName[RAS_MaxEntryName+1];在Delphi中:szEntryName:Array[0..RAS_MaxEntryName]ofChar;为什么不是数组[0..RAS_MaxEntryName+1]ofChar?一个C数组从0开始到声明指定元素的数目。因此,在Delphi中,数组[0..RAS_MaxEntryName+1]相当于C中[RAS_MaxEntryName+2]。3.5枚举类型:方法1typedefenum_FINDEX_INFO_LEVELS{FindExInfoStandard,FindExInfoMaxInfoLevel}FINDEX_INFO_LEVELS;翻译成Delphi:TypeTFindExInfoLevels=(FindExInfoStandard,FindExInfoMaxInfoLevel);该项目FindExInfoStandard序号值是0。在Delphi中每个计数从0开始。方法2:另一种情况:Typedefenum_ACL_INFORMATION_CLASS{AclRevisionInformation=1,AclSizeInformation}ACL_INFORMATION_CLASS声明中“=1”强制在C开始序号值为1。这是在Delphi中不可能的。3.6结构、记录3.6.1简单结构结构类型:在Delphi中的RECORD类型与C结构相似。结构通常用typedef关键字定义,但它也有可能用#define。C中的形式如下:{Struct|Union}[OptIdentifier][TagName]
{
FieldDefinitions
[;
...]}
[Name[...]]你可以忽略tagname。这是为后续的参考结构。如何在一个结构内的定义字段:#defineRASENTRYNAMEAstructtagRASENTRYNAMEARASENTRYNAMEA{DWORDdwSize;CHARszEntryName[RAS_MaxEntryName+1];};此声明定义了一个名叫RASENTRYNAMEA记录(结构)。Delphi风格的名字为TRASENTRYNAMEA。这个结构包含两个字段:一是具有指定类型为DWORD的dwSize。第二是字符数组,有ras_maxentryname+1个元素。翻译成delphiTYPEPRASEntryName=^TRASEntryNameTRASEntryName=RecorddwSize:DWORD;szEntryName:Array[0..RAS_MaxEntryName]ofCharend记住,你不可能声明的字符数组的范围为0到ras_maxentryname+1。原因是,在C元素的数目被指定的,但在Delphi中的元素范围被指定。3.6.2结构中的联合类型unions在结构中C联合类型可翻译为Delphi记录变体类型。在联合结构中的块声明不连续但覆盖。typedefstruct_PROCESS_HEAP_ENTRY{PVOIDlpData;DWORDcbData;BYTEcbOverhead;BYTEiRegionIndex;WORDwFlags;union{struct{HANDLEhMem;DWORDdwReserved[3];}Block;struct{DWORDdwCommittedSize;DWORDdwUnCommittedSize;LPVOIDlpFirstBlock;LPVOIDlpLastBlock;}Region;};}PROCESS_HEAP_ENTRY,*LPPROCESS_HEAP_ENTRY,*PPROCESS_HEAP_ENTRY;翻译成Delphi:typePProcessHeapEntry=^TProcessHeapEntry;TProcessHeapEntry=RecordlpData:Pointer;cbData:DWord;cbOverhead:Byte;iRegionIndex:Byte;wFlags:Word;caseIntegerof0:(Block:RecordhMem:ThandleReserved:Array[0..2]ofDWord;end);1:(Region:RecorddwCommittedSize:DWord;dwUnCommittedSize:DWord;lpFirstBlock:Pointer;lpLastBlock:Pointerend);end;记录的变体部分以CaseIntegerof开头。每个变体由一个序数值确定。这个整数值当做类型被使用时没有意义,但是所必需的声明。请注意一个变体(case-)记录和一个没有CASE-声明记录之间的区别以下翻译错了:typePPRocessHeapEntry=^TProcessHeapEntry;TProcessHeapEntry=RecordlpData:Pointer;cbData:DWord;cbOverhead:Byte;iRegionIndex:Byte;wFlags:Word;Block:RecordhMem:ThandleReserved:Array[0..2]ofDWord;end;Region:RecorddwCommittedSize:DWord;dwUnCommittedSize:DWord;lpFirstBlock:Pointer;lpLastBlock:Pointerend;end;这个错误的翻译会引起Block和Region在内存中是连续的,不重叠,如下:LpData,cbData,cbOverhead,iRegionIndex,wFlagsHMem,dwReservedDwCommittedSize,dwUnCommittedSize,lpFirstBlock,lplastBlock3.6.3packedrecord压紧记录(对齐)如果记录压紧(对齐),然后使用16位或32位的首字节的字段开始字节被对齐(也就是记录)。这明显加快CPU访问字段,但消耗更多的内存。旧的API(从16位以来)通常使用的包装结构(一个或两个字节对齐)。这是16位Delphi默认:如果你写record或packedrecord,在Delphi1没有区别。delphi32默认下为四字节对齐,虽然一些API在Win32下使用packedrecords。在API中,知道哪种对齐的类型被使用是很重要的,因为记录的大小取决于对齐。下面的例子说明了2和4字节编码对齐之间差异:TmyRecNotPacked=RecordFieldA:Word;FieldB:LongInt;FieldC:Byte;End;TmyRecPacked=packedRecordFieldA:Word;FieldB:LongInt;FieldC:Byte;End;Offset01234567891011TMyRecNoPackedAA..BBBBC...TMyRecPackedAABBBBC现在,如何判断是否需要压紧。在微软的API中,使用了两种方法。一是明确和简单的:#PRagma
pack(n)如果n是1或2使用packed关键词,但如果n是4不要使用packed。然而,微软使用#include<filename>通过在包含文件中放置压紧编译指示字来控制压紧。下列包含文件用于控制压紧方法:#include意义压紧请求pshpack1.h#pragmapack(1)Yespshpack2.h#pragmapack(2)Yespshpack3.h#pragmapack(3)Yespshpack4.h#pragmapack(4)NoPoppack.hBacktopreviouspacking?如果头文件包含以下行:#include<pshpack1.h>你可以把它理解为#pragmapack(1),并且在记录中使用packed关键词,从现在直到遇到另外一个pshpack?.h或poppack.H的包含。四字节对齐的(非压紧记录)在delphi32是默认。但是如果用户更改编译器选项和关闭4字节对齐咋办?如果你需要确保4字节对齐启用,您必须在单元的顶部插入下面的行:{$ALIGNON}单元头必须看起来至少像这样:UnitMyUnit;{$ALIGNON}你可以用{$ALIGN}指令显式代替使用packed关键词,太,但我更喜欢明确的压紧,因为它覆盖{$ALIGNON}并完全确定。注:一个字段的长度是奇数字节提出了一个问题,如果你遇到#pragmapack(2)和使用packed关键词。该字段在字节边界上将关闭压紧,当他在字边界上被压紧时。将寻求处理这种情况的解决方案。4.宏命令在C中可以定义宏。宏在Delphi中是不可用的,所以必须翻译C-宏功能来使用它。在大多数情况下,基于文档中关于他的信息来翻译宏比直接代码翻译更容易些。一个宏的示例:#definePRIMARYLANGID(lgid)((Word)(lgid)&0x03ff)在这里,很显然,宏观接受整数。这个宏的有效的翻译是:FunctionPRIMARYLANGID(lgid:DWord):DWord;BeginResult:=lgidand$03FFEnd;下面的宏接受任何数据类型作为参数:#definemax(a,b)(((a)>(b))?(a):(b))比较参数a和一个参数b值并返回较大值。因此,我们可以通过任何数据类型的函数,使用的变体变量:FunctionMax(A,B:Variant):Variant;BeginIfA>BthenResult:=AelseResult:=BEnd;我推荐基于对宏的文档的基础上进行Delphi的转移。有时不可能把C宏以1:1的翻译成delphi,并保证对应关系。例如,一些头文件在#define语句中使用宏来声明常量。这是来自CLUSAPI头文件的一个例子。#defineCLUSPROP_SYNTAX_VALUE(type,format)((DWORD)((type<<16)|format))随后的声明使用宏命名CLUSTER_PROPERTY_SYNTAX计算常数的值:typedefenumCLUSTER_PROPERTY_SYNTAX{CLUSPROP_SYNTAX_ENDMARK=CLUSPROP_SYNTAX_VALUE(CLUSPROP_TYPE_ENDMARK,CLUSPROP_FORMAT_UNKNOWN),CLUSPROP_SYNTAX_NAME=CLUSPROP_SYNTAX_VALUE(CLUSPROP_TYPE_NAME,CLUSPROP_FORMAT_SZ),CLUSPROP_SYNTAX_RESCLASS=CLUSPROP_SYNTAX_VALUE(CLUSPROP_TYPE_RESCLASS,CLUSPROP_FORMAT_DWORD),在Delphi中我们不能这样做,此外,Delphi不允许枚举项的值被分配值。该宏为了翻译成delphi必须解决。我们可以把#define语句翻译为以下的Delphi函数:FunctionCLUSPROP_SYNTAX_VALUE(dwType:DWORD;dwFormat:DWORD):DWORD;BeginResult:=(dwTypeshl16)ordwFormat;End;然而,函数调用在常量声明中是不可能的。为此,我们声明常数如下,也就是直接将内容计算出来:CONSTCLUSPROP_SYNTAX_ENDMARK=CLUSPROP_TYPE_ENDMARKshl16orCLUSPROP_FORMAT_UNKNOWN;CLUSPROP_SYNTAX_NAME=CLUSPROP_TYPE_NAMEshl16orCLUSPROP_FORMAT_SZ;CLUSPROP_SYNTAX_RESCLASS=CLUSPROP_TYPE_RESCLASSshl16orCLUSPROP_FORMAT_DWORD;实际上,在这种情况下,我建议将宏作为一个整体为一个函数,它可以提供给应用程序有用。5条件句6函数6.1基本的让我们用下面的c-声明作为声明一个函数的一个例子:WINADVAPIBOOLWINAPIControlService(SC_HANDLEhService,DWorddwControl,LPSERVICE_STATUSlpServiceStatus);[Options]
ReturnValueType[Options]
FunctionName
(
[ParameterList]
)ReturnValueType:指定函数的返回值的类型。在上面的例子中返回值的类型是布尔。如果函数没有返回值是使用关键字void,在Delphi中的翻译成一个过程。请注意,这个类型的标识符也可以被“隐藏”在一个使用#define定义的标识符中。Options:Options可以指定一个标志象征的调用约定,且/或其他关键词告诉编译器在问题中如何处理函数。最重要的一项是调用约定。在WindowsAPI的调用约定的头文件,通常是“隐藏”的在使用#define标识符中声明,所以你要看什么的定义。上面的例子使用WinAPI符号,类似为__stdcall。这是翻译的必要,太。每个Options项目为影响和丢弃或执行必须进行评估的。FunctionName:指定函数名ParameterList:传递给函数的参数列表,使用“,“分隔符。参数声明为通过类型标识符或通过类型标识符+参数名称的组合。6.2调用约定参考示例:WINADVAPIBOOLWINAPIControlService(SC_HANDLEhService,DWORDdwControl,LPSERVICE_STATUSlpServiceStatus);返回值的类型是布尔。现在让我们看一看在WINAPI的定义。WINAPI定义在windef.h中,为以下方式:#defineWINAPI__stdcall该__stdcall关键字告诉C编译器为函数使用standard-call调用约定,所以我们必须声明该函数使用stdcall,因为默认的调用约定是注册在Delphi中。该函数接受三个参数。第一个是一个SC_HANDLE型参数,第二个是DWORD,第三是一个指向PServiceStatus结构。以下是delphi的翻译:FunctionControlService(hService:SC_Handle;dwControl:DWORD;lpServiceStatus:PServiceStatus):Bool;stdcall;注意:1.SC_Handle已被定义在WinSvc.pas中2.C变量hService采用H作为一个handle类型的首字母似乎与Delphi约定有冲突。虽然它似乎需要使用另一种(hndservice:hcontrolservice,例如),Delphi将在参数列表中接受重复的名称(例如:HWND:hWnd)。因为Borland作品,我会建议转换他。让我们看一看在另一个函数声明:ULONG(FARPASCALMAPISENDDOCUMENTS)(ULONGulUiparam,LPSTRlpszDelimChar,LPSTRlpszFilePaths,LPSTRlpszFileNames,ULONGulReserved);嗯,这个声明包含一个陷阱。关键词Pascal被用来指定Pascal-calling约定,它通常是用16位的windows中。但不是在Win32。看看下面的行(在windef.h文件):#definePASCAL__stdcall该windef.h头声明PASCAL作为__stdcall,它指定stdcall调用约定,因此你也必须在这种情况下使用stdcall调用约定。注意:1.它是非常重要的,通过追踪所有#include文件中#defines可能影响翻译。2.在delphi中
FAR
关键词可以被忽略。7.连接有两种方法可以链接DLL并导入函数。如果DLL一肯定在客户机中的可用,静态链接是很容易的,并且是推荐的方法。如果DLL是可选的最好使用动态链接(运行时链接)来确保应用程序不因为缺少DLL(可能是不重要的)而失败。静态链接编码直接调用库DLL的的入口代码,不检查是否可以链接到库。动态链接库DLL调用,应用程序的运行时,有能力处理库的连接问题。动态链接可以发生在启动时,或在程序运行时调用由用户所需要的库。Borland通常使用静态链接,但一些API翻译使用动态链接。一个是SMAPI翻译的例子(MAPI.PAS)。让我们看一看连接一个DLL和导入函数两个方法。7.1静态链接如果使用静态链接,简单地声明函数原型,在接口部分和实现部分下面的方法:INTERFACE{Function|Procedure}FunctionName[FunctionDeclaration;]IMPLEMENTATION{Function|Procedure}FunctionNameexternalDLLName[name'FunctionExportName'];函数原型的翻译在前面的部分。对于导入函数?在实现部分不强制包括函数的参数部分,但如果你愿意也可以。作为一个例子来说明如何导入函数,让我们用从kernel32.dll的OpenEvent函数。有两种函数实现方法,使用Unicode(16bitwidechar)和使用ANSI字符(8位字符)的支持。以下是C函数WINBASEAPIHANDLEWINAPIOpenEventA(DWorddwDesiredaccess,BOOLbInheritHandle,LPCSTRlpName);WINBASEAPIHANDLEWINAPIOpenEventW(DWORDdwDesiredAccess,BOOLbInheritHandle,LPCWSTRlpName);#ifdefUNICODE#defineOpenEventOpenEventW#else#defineOpenEventOpenEventA#endif//!UNICODE三函数声明:OpenEventA是函数的的ANSI字符版本,OpenEventW为宽字符(Unicode)版本,和OpenEvent。如果UNICODE符号被声明,OpenEvent使用的函数的widechar版(OpenEventW)。如果UNICODE符号未被声明则使用ANSI字符版本的OpenEventA。INTERFACE{...}functionOpenEventA(dwDesiredAccess:DWORD;bInheritHandle:BOOL;lpName:PAnsiChar):THandle;stdcall;functionOpenEventW(dwDesiredAccess:DWORD;bInheritHandle:BOOL;lpName:PWideChar):THandle;stdcall;{$IFDEFUNICODE}functionOpenEvent(dwDesiredAccess:DWORD;bInheritHandle:BOOL;lpName:PWideChar):THandle;stdcall;{$ELSE}functionOpenEvent(dwDesiredAccess:DWORD;bInheritHandle:BOOL;lpName:PChar):THandle;stdcall;{$ENDIF}{...}IMPLEMENTATIONConstkernel32='kernel32.dll';{...}functionOpenEventA;externalkernel32name'OpenEventA';functionOpenEventW;externalkernel32name'OpenEventW';{$IFDEFUNICODE}functionOpenEvent;externalkernel32name'OpenEventW';{$ELSE}functionOpenEvent;externalkernel32name'OpenEventA';{$ENDIF}{...}7.2动态链接动态链接在运行时被使用。在JediEnvironment中处理静态和动态的连接因为静态和动态链接都有自身的优势,我们必须在Jedi单元中准备支持这两种技术。然而,静态链接是默认的。为了支持多种方法,编译器使用符号。两个编译器符号象征动态链接如下:如果Xxxx_DYNLINK被定义则DLL必须在启动时被动态链接(必须在启动的initialization部分)。如果Xxxx_LINKONREQUEST被定义则DLL动态链接,不在启动部分,但由用户需求决定。Xxxx是API的名称,例如MAPI_DYNLINK或MAPI_LINKONREQUEST。如果没有定义符号,则使用静态链接。各进口单元应实现的函数如下:FunctionXxxxInitAPI:Boolean;ProcedureXxxxFreeAPI;FunctionXxxxCheckAPI:Boolean;如果符号Xxxx_LINKONREQUEST被定义则函数XxxxInitAPI和和过程XxxxFreeAP对用户可用。用户可以调用这个函数来加载或释放DLL。XxxxInitAPI返回TRUE,则加载的DLL成功。如果Xxxx_DYNLINK被定义,但无Xxxx_LINKONREQUEST,在初始化部分这些函数将被用于内部使用来加载或卸载DLL,但他们对用户不可用。如果API是可用的则函数XxxxCheckAPI返回TRUE,如果DLL使用XxxxInitAPI预加载成功那么其返回值为TRUE。当使用静态链接,其返回值总是TRUE。下面是如何在翻译中处理符号的一个例子:unitapisample;interfaceUSESWindows,JediUtil;//有两个条件定义。一个在启动时使用动态运行时连接上,另外一个在请求时连接。事实上,唯一的区别是,如果upon-request符号被定义则库在initialization部分不被加载。两个符号开头部分使用API,如果是TAPI名字。在这个例子中,它是APISAMPLE。APISAMPLE_DYNLINK信号表明API应该在启动时通过LoadLibrary和GetProcAddress被链接。APISAMPLE_LINKONREQUEST信号表明库在启动时不被连接,但是通过initialization过程。/因为这两个符号大
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- DB1410-T 130-2022 园林绿化管养规范
- 项目2 学会养绿萝说课稿-2025-2026学年小学劳动一年级上册湘人版《劳动实践指导手册》
- 2025建筑设备自考试题及答案
- 2025年乡村医生资格考试题库含答案
- 2025年公务员面试真题及答案
- 2025年低压电工证考试题库附答案
- 2025宁阳社工考试题库及答案
- 2025保育学自考试题及答案
- 四级营养师技能考核考试真题及答案(2025年新版)
- 2025年中级经济师题库附参考答案
- 2025河南省大河控股有限公司所管企业第二批社会招聘2人考试模拟试题及答案解析
- 2025上海东滩建设集团有限公司招聘考试参考试题及答案解析
- 2025年中医师承及确有专长考核真题(附答案)
- 2025年湖南大学事业编制管理辅助岗位招聘58人笔试备考题库及答案解析
- 2025年西藏国家公务员考录《行测》真题及参考答案
- 云南省云南大附中(一二一校区)2026届数学七上期末统考试题含解析
- 热管安全培训课件
- 河南省重点高中2025-2026学年高一上学期开学检测语文试题及答案
- 农业遥感耕地资源调查方案
- 人工智能+金融科技经济增长趋势研究报告
- 充电桩维修安全培训课件
评论
0/150
提交评论