从其它平台迁移而来
由于长期使用Delphi
开发,又与硬件打交道比较多,不可避免地要与标准C动态库
进行对接,而往往厂家提供的SDK又偏偏没有Delphi
的,无奈也就只好自己改写.h
头文件了。写得多了,也就有了一点点心得,在这里就分享出来,也好与大家互相交流、学习。
知识点
-
标准C动态库使用的都是单字节字符。
-
Delphi 2007
以前默认使用的是单字节字符,即Ansi
编码,也就是说Char = AnsiChar
、PChar = PAnsiChar
、string = AnsiString
;Delphi 2009
以后使用的是双字节字符,即Unicode
编码,也就是说Char = WideChar
、PChar = PWideChar
、string = WideString
。为了保证改写后的.pas
文件适用于Dephi的各个版本,应避免使用Char
、PChar
、string
这种类型不明确的数据类型(通常情况下使用AnsiChar
、PAnsiChar
、AnsiString
即可,但特殊情况要特殊处理)。 -
@string[1]
才是字符串首地址。 -
Delphi中可以把
AnsiString
当作缓冲区来使用,某些情况下比array of Byte
要方便得多。 -
对字符串变量第一次使用
SetLengh
时会重新分配内存,第二次使用时,若设定的长度比第一次小,则只会进行截断而并不改变已写入的内容,该特性在使用API返回字符串
时非常好用。 -
Delphi中的
record
是进行过字节对齐的,执行效率高,但占用空间比看到的会略大;packed record
是未进行过字节对齐的,执行效率略低,但占用空间与看到的保持一致。也就是说,Delphi中packed record
才是与C中的struct
等同。 -
在Delphi中
packed record
配合case
可以实现C中的union
,具体是否等同还要看实际定义的字节是否一致(需要对每种数据类型占用的空间十分熟悉)。 -
标准C动态库的API函数或回调函数,在Delphi中均要使用
stdcall;
来修饰,以确保传参顺序一致。
数据类型对应关系
C/C++ 类型 | Delphi 基本类型 | Delphi Window 单元类型 | 说明 |
---|---|---|---|
char | ShortInt / Int8 | 8位有符号整型 | |
char* | PShortInt | ||
unsigned char / BYTE | Byte / UInt8 | UCHAR | 8位无符号整型,字节型 |
unsigned char* | PByte | LPBYTE / PUCHAR | |
short | SmallInt / Int16 | SHORT | 16位有符号整型 |
short* | PSmallInt | PSHORT | |
unsigned short | Word / UInt16 | WORD | 16位无符号整型 |
unsigned short* | PWord | PUSHORT | |
int / long | Integer / Longint / Int32 | LONG | 32位有符号整型 |
int* / long* | PInteger / PLongInt | PLONG | |
unsigned / unsigned int / unsigned long | Cardinal / LongWord / UInt32 | DWORD / UINT / ULONG / ULONG32 | 32位无符号整型 |
unsigned int* / unsigned long* | PCardinal / PLongWord / PUint32 | PDWORD / PUINT / PULONG | |
long long / __int64 | Int64 | LONG64 / LONGLONG | 64位有符号整型 |
long long* / __int64* | PInt64 | PLONG64 | |
unsigned long long / unsigned __int64 | UInt64 | ULONG64 / ULONGLONG / DWORD64 | 64位无符号整型 |
unsigned long long* / unsigned __int64* | PUInt64 | PULONG64 / PULONGLONG / PDWORD64 | |
float | Single / Float32 | 32位单精度浮点型 | |
float* | PSingle | ||
double | Double / Float64 | 64位双精度浮点型 | |
double* | PDouble | ||
long double | Extended | 10字节浮点型 | |
char | AnsiChar | 单字节字符 | |
char* | PAnsiChar | LPSTR / LPCSTR | |
char** | PPAnsiChar | ||
wchar_t / WCHAR | WideChar | WCHAR | 双字节字符 |
wchar_t* | PWideChar | PWChar / LPWSTR / LPCWSTR | |
wchar_t** | PPWideChar | ||
任意1字节类型 | Boolean / ByteBool | 1字节布尔型 | |
任意1字节类型指针 | PBoolean / PByteBool | ||
任意2字节类型 | WordBool | 2字节布尔型 | |
任意2字节类型指针 | PWordBool | ||
BOOL | LongBool | BOOL | 4字节布尔型 |
BOOL* | PLongBool | PBOOL | |
void* | Pointer | PVOID / LPVOID / LPCVOID | 无类型指针 |
void** | PPointer | PPVOID |
升华
有了以上知识,把.h
头文件改为.pas
单元是不成问题了,但改写后的API是否好用,还要打个问号。
比如有以下API:
|
|
按前面提到的改为.pas
单元:
|
|
改写没有任何问题,但是不如以下这种直观、方便,毕竟有不少人对指针和地址还是相当恐惧的。
|
|
假如以上API为:
|
|
那么,生硬的改成
|
|
就不如改为
|
|
改写不仅仅是为了改写,更是为了调用。当然,若是再加一层封装来给其它单元调用,甚至直接封装成类,那是再好不过了!