在Delphi編程中使用C語言代碼 
  
   Windows下編程的工具有很多,例如VB,Delphi,VC等等.我在這里不想討論"它們的具體哪個(gè)更好一點(diǎn)"這種幼稚的問題.玩過DOS程序設(shè)計(jì)的人都知道,DOS下很多語言的實(shí)質(zhì)核心還是調(diào)用系統(tǒng)提供的匯編中斷函數(shù).到了Windows下,它就變成了我們常說的API了.而在Windows下寫程序很多時(shí)候都是調(diào)用API,語言,只不過是一個(gè)表達(dá)工具而已.
   我現(xiàn)在已經(jīng)參加工作大約有半年左右,我們公司是用Borland公司的Delphi作為主開發(fā)工具.本著未偏袒任何一個(gè)工具的立場(chǎng),我說句公道話:Delphi是目前Win32下開發(fā)程序的最快速,最有效率的工具.
   Delphi適合用來開發(fā)應(yīng)用程序,但是有時(shí)侯一些底層的東西可以直接使用C語言來開發(fā).我在公司經(jīng)常開發(fā)跟硬件相關(guān)的項(xiàng)目,而很多硬件的SDK包是用C來寫的.這個(gè)時(shí)候我一般把它們轉(zhuǎn)換成Delphi(PASCAL)語法的代碼.下面談一下我的個(gè)人粗淺經(jīng)驗(yàn).因?yàn)楫?dāng)時(shí)學(xué)校教的是Pascal語言,所以我對(duì)C語言并不是太熟手.下面的觀點(diǎn)或者代碼如有錯(cuò)漏之處希望高手們放小弟一馬:) 
一:將C語言的程序編譯成DLL供Delphi調(diào)用.這種方法過于簡單,而且需要額外帶一個(gè)DLL文件,所以不在本文的討論范圍之內(nèi).
二:直接轉(zhuǎn)換C語言代碼到DELPHI代碼
  C語言的函數(shù)格式與Delphi不同,它們是函數(shù)返回類型在前,函數(shù)聲明在后.對(duì)于沒有任何返回類型的函數(shù)則定義為VOID類型.
  例如:Delphi中函數(shù)function MyFunction:(intIN:integer):Bool;相應(yīng)的C語言代碼就變成Bool MyFunction(int intIN);又例如procedure MyProcedure;====>void MyProcedure;采用這種方法,一般要求對(duì)C語言比較熟悉.我一般是采用這種方法.下面是我收集整理的自己常用的Delphi與C之間的類型對(duì)應(yīng)表.其中左邊是C類型,右邊是對(duì)應(yīng)的Delphi類型:
ABC -> TABC 
ACCEL -> TAccel 
ATOM -> TAtom 
BITMAP -> TBitMap 
BITMAPCOREHEADER -> TBitmapCoreHeader 
BITMAPCOREINFO -> TBitmapCoreInfo 
BITMAPFILEHEADER -> TBitmapFileHeader 
BITMAPINFO -> TBitmapInfo 
BITMAPINFOHEADER -> TBitmapInfoHeader 
BOOL -> Bool 
CBT_CREATEWND -> TCBT_CreateWnd 
CBTACTIVATESTRUCT -> TCBTActivateStruct 
CHAR -> Char 
CHAR* -> PChar 
CLIENTCREATESTRUCT -> TClientCreateStruct 
COLORREF -> TColorRef 
COMPAREITEMSTRUCT -> TCompareItemStruct 
COMSTAT -> TComStat 
CREATESTRUCT -> TCreateStruct 
CTLINFO -> TCtlInfo 
CTLSTYLE -> TCtlStyle 
CTLtype -> TCtltype 
DCB -> TDCB 
DDEAACK -> TDDEAck 
DDEADVISE -> TDDEAdvise 
DDEDATA -> TDDEData 
DDEPOKE -> TDDEPoke 
DEBUGHOOKINFO -> TDebugHookInfo 
DELETEITEMSTRUCT -> TDeleteItemStruct 
DEVMODE -> TDevMode 
DOUBLE -> Double 
DRAWITEMSTRUCT -> TDrawItemStruct 
DWORD -> LongInt 
ENUMLOGFONT -> TEnumLogFont 
EVENTMSG -> TEventMsg 
FARPROC -> TFarProc 
FIXED -> TFixed 
FLOAT -> Single 
GLYPHMETRICS -> TGlyphMetrics 
HANDLE -> THandle 
HANDLETABLE -> THandleTable 
HARDWAREHOOKSTRUCT -> THardwareHookStruct 
HELPWININFO -> THelpWinInfo 
INT -> Integer 
KERNINGPAIR -> TKerningPair 
LOGBRUSH -> TLogBrush 
LOGFONT -> TLogFont 
LOGPALETTE -> TLogPalette 
LOGPEN -> TLogPen 
LONG -> LongInt 
LONG DOUBLE -> Extended 
LONG INT -> LongInt 
LPSTR -> PChar 
LPWSTR -> PWideChar 
MAT2 -> TMat2 
MDICREATESTRUCT -> TMDICreateStruct 
MEASUREITEMSTRUCT -> TMeasureItemStruct 
MENUITEMTEMPLATE -> TMenuItemTemplate 
MENUITEMTEMPLATEHEADER -> TMenuItemTemplateHeader
METAFILEPICT -> TMetaFilePict 
METAHEADER -> TMetaHeader 
METARECORD -> TMetaRecord 
MINMAXINFO -> TMinMaxInfo 
MOUSEHOOKSTRUCT -> TMouseHookStruct 
MSG -> TMsg 
MULTIKEYHELP -> TMultiKeyHelp 
NCCALCSIZE_PARAMS -> TNCCalcSize_Params 
NEWTEXTMETRIC -> TNewTextMetric 
OFSTRUCT -> TOFStruct 
OUTLINETEXTMETRIC -> TOutlineTextMetric 
PAINTSTRUCT -> TPaintStruct 
PALETTEENTRY -> TPaletteEntry 
PANOSE -> TPanose 
PATTERN -> TPattern 
POINTFX -> TPointFX 
PSTR -> PChar 
PWSTR -> PWideChar 
RASTERIZER_STATUS -> TRasterizer_Status 
RGBQUAD -> TRGBQuad 
RGBTRIPLE -> TRGBTriple 
SEGINFO -> TSegInfo 
SHORT -> SmallInt 
SHORT INT -> SmallInt 
SIZE -> TSize 
TEXTMETRIC -> TTextMetric 
TPOINT -> TPoint 
TRECT -> TRect 
TTPOLYCURVE -> TTTPolyCurve 
TTPOLYGONHEADER -> TPolygonHeader 
UINT -> Word 
UNSIGNED -> Word 
UNSIGNED CHAR -> Byte 
UNSIGNED INT -> Word 
UNSIGNED LONG -> LongInt(DWORD) 
UNSIGNED LONG INT -> LongInt 
UNSIGNED SHORT -> Word 
UNSIGNED SHORT INT -> Word 
VOID* -> Pointer 
WINDOWPLACEMENT -> TWindowPlacement 
WINDOWPOS -> TWindowPos 
WNDCLASS -> TWndClass 
WORD -> Word 
三:在Delphi中直接鏈接C語言的OBJ文件.
  這種方法的好處在于最終EXE不用帶任何外部文件.也不用對(duì)C語言過于熟悉.
  我們都知道,代碼在編譯成可執(zhí)行文件(或DLL,OCX文件,下同)之前,都必須得先生成OBJ文件(DELPHI一般是DCU文件,但也可以通過編輯編譯選項(xiàng)生成OBJ文件),然后把OBJ文件和資源文件(*.RES)鏈接成最終的可執(zhí)行文件.利用這個(gè)方法,我們可以直接把OBJ文件鏈接到我們的程序里面.
  不過需要注意的是,編譯器不同,生成的OBJ文件也不一樣.Microsoft的編譯器生成的OBJ文件是COFF格式,而Borland的C++Builder生成的是OMF格式.因?yàn)槲覀冃枰贒elphi中鏈接,所以必須使用CBC,或者Borland官方站點(diǎn)帶的免費(fèi)編譯工具.下面我們通過一個(gè)簡單的例子來說明具體操作步驟:
  這個(gè)例子是簡單的提供一個(gè)函數(shù),用來判斷一個(gè)文件是否為Dat格式的VCD文件.頭文件聲明如下:
/*
文件名稱:DatFormat.h
*/
#ifndef DatFormat_H
#define DatFormat_H
#include <windows.h>
#pragma pack(push, 1)//這個(gè)與下面的配對(duì),一般用到記錄類型的時(shí)候需要定義,這里實(shí)際不用
#ifdef __cplusplus
extern "C" {
#endif
extern BOOL CheckIsDatFile(const char * FileName,BOOL *IsDatFile);
#ifdef __cplusplus
}
#endif
#pragma pack(pop)
#endif // DatFormat_H
 具體實(shí)現(xiàn)代碼DatFormat.c如下:
#include "DatFormat.h"
BOOL CheckIsDatFile(const char * FileName,BOOL *IsDatFile)
/*
函數(shù)說明:該函數(shù)用于判斷一個(gè)文件是否為Dat文件(即VCD文件)格式.
參數(shù):
IN:
FileName:欲判斷的文件名稱
IN,OUT:
IsDatFile:是否為Dat格式文件
OUT:
讀文件失敗返回FALSE,否則返回TRUE.
------------------------------------
作者:陳經(jīng)韜.2004,01,17. http://www.,lovejingtao@21cn.com/
*/
{
HANDLE hFile;
DWORD dwBytesRead;
BOOL re;
char MyBuf[4];
*IsDatFile=FALSE;
//建立讀文件句柄
hFile = CreateFile(FileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
0);
if (hFile == INVALID_HANDLE_VALUE) return FALSE;
//讀文件
re = ReadFile(hFile,
&MyBuf,
4,
&dwBytesRead,
NULL);
if (dwBytesRead!=4)
{
CloseHandle(hFile);
return FALSE;
}
//讀文件失敗的時(shí)候
if (re!=TRUE)
{
CloseHandle(hFile);
return FALSE;
}
CloseHandle(hFile);
*IsDatFile=(MyBuf[0]==‘R‘ && MyBuf[1]==‘I‘ && MyBuf[2]==‘F‘ && MyBuf[3]==‘F‘);
return(TRUE);
}
 運(yùn)行CBC,新建一個(gè)工程,然后把DatFormat.c添加到工程里面,編譯整個(gè)工程,將得到我們需要的OBJ文件:DatFormat.OBJ.然后我們關(guān)閉CBC即可,因?yàn)橄旅娌辉傩枰玫剿?
 運(yùn)行Delphi,新建一個(gè)工程并保存.然后把DatFormat.OBJ拷貝到它的目錄之下.在單元的implementation下面添加如下代碼:
{$LINK ‘DatFormat.obj‘} //鏈接外部OBJ文件
function _CheckIsDatFile(const FileName:Pchar;IsDatFile:PBool):Bool;cdecl;external;//定義函數(shù).其中cdecl進(jìn)棧方式說明采用C語言格式傳遞參數(shù).external說明是個(gè)外部聲明函數(shù).
 注意函數(shù)聲明的原形與C定義的不一樣.必須在前面添加一個(gè)下劃線.原因是因?yàn)榫幾g器的鏈接符號(hào)中.C與C++是不一樣的.因?yàn)檫@個(gè)不是本文重點(diǎn),所以這里不作討論.請(qǐng)感興趣的朋友自行參閱相關(guān)資料.
 然后我們寫如下代碼調(diào)用此函數(shù):
procedure TFrmMain.Button1Click(Sender: TObject);
var
IsDatFile:Bool;
begin
if OpenDialog1.Execute then
if _CheckIsDatFile(Pchar(OpenDialog1.FileName),@IsDatFile) then
if IsDatFile then ShowMessage(‘恭喜!該文件是一個(gè)Dat格式的視頻文件!‘)
else ShowMessage(‘不好意思,該文件不是一個(gè)Dat格式的視頻文件!‘)
else ShowMessage(‘讀文件錯(cuò)誤!‘);
end;
 編譯這個(gè)程序,將得到一個(gè)干凈的可執(zhí)行EXE文件了.
四:C++Builder中使用Delphi單元
 這個(gè)實(shí)際是題外話了,不過這里還是提一提:假設(shè)我們有一個(gè)獲取BIOS密碼的Delphi單元
unit AwardBiosPas;
{=======================================================
項(xiàng)目: 在Delphi編程中使用C語言代碼- 演示程序
模塊: 獲取BIOS密碼單元
描述:
版本:
日期: 2004-01-17
作者: 陳經(jīng)韜.lovejingtao@21cn.com,http://www./
更新: 2004-01-17
=======================================================}
interface
uses
windows, SysUtils;
function My_GetBiosPassword: string;
implementation
function CalcPossiblePassword(PasswordValue: WORD): string;
var
I: BYTE;
C: CHAR;
S: string[8];
begin
I := 0;
while PasswordValue <> 0 do
begin
Inc(I);
if $263 > PasswordValue then
begin
if $80 > PasswordValue then
S[I] := CHAR(PasswordValue)
else if $B0 > PasswordValue then
S[I] := CHAR(PasswordValue and $77)
else if $11D > PasswordValue then
S[I] := CHAR($30 or (PasswordValue and $0F))
else if $114 > PasswordValue then
begin
S[I] := CHAR($64 or (PasswordValue and $0F));
if ‘0‘ > S[I] then
S[I] := CHAR(BYTE(S[I]) + 8);
end
else if $1C2 > PasswordValue then
S[I] := CHAR($70 or (PasswordValue and $03))
else if $1E4 > PasswordValue then
S[I] := CHAR($30 or (PasswordValue and $03))
else
begin
S[I] := CHAR($70 or (PasswordValue and $0F));
if ‘z‘ < S[I] then
S[I] := CHAR(BYTE(S[I]) - 8);
end;
end
else
S[I] := CHAR($30 or (PasswordValue and $3));
PasswordValue := (PasswordValue - BYTE(S[I])) shr 2;
end;
S[0] := CHAR(I);
PasswordValue := I shr 1;
while PasswordValue < I do
begin {this is to do because award starts calculating with the last letter}
C := S[BYTE(S[0]) - I + 1];
S[BYTE(S[0]) - I + 1] := S[I];
S[I] := C;
Dec(I);
end;
CalcPossiblePassword := S;
end;
function readcmos(off: byte): byte;
var
value: byte;
begin
asm
xor ax, ax
mov al, off
out 70h, al
in al, 71h
mov value, al
end;
readcmos := value;
end;
function My_GetBiosPassword: string;
var
superpw, userpw: word;
begin
if Win32Platform <> VER_PLATFORM_WIN32_NT then //不是NT
begin
pchar(@superpw)[0] := char(readcmos($1C));
pchar(@superpw)[1] := char(readcmos($1D));
pchar(@userpw)[0] := char(readcmos($64));
pchar(@userpw)[1] := char(readcmos($65));
Result:= (‘************BIOS密碼**********************‘)+#13+‘超級(jí)用戶密碼為:‘ + CalcPossiblePassword(superpw) + #13 + ‘用戶密碼為:‘ + CalcPossiblePassword(userpw);
end
else
Result := ‘用戶系統(tǒng)為NT,無法獲取BIOS密碼!‘;
end;
end.
 如何直接在CBC中使用它呢?新建一個(gè)CBC工程,然后把這個(gè)單元加到項(xiàng)目里面去.具體操作為:Add to Project--->文件類型:pascal unit(*.pas),然后Build Demo1.這個(gè)時(shí)候?qū)⒃贏wardBiosPas.pas的同目錄下生成一個(gè)AwardBiosPas.hpp文件.把它引用到我們的需要調(diào)用的單元.然后直接調(diào)用即可:
void __fastcall TFrmMain::Button1Click(TObject *Sender)
{
ShowMessage(My_GetBiosPassword());
}
五:其它方法.當(dāng)然可以用RES將C語言生成的二進(jìn)制文件,但這個(gè)方法與第一種方法差不多.優(yōu)點(diǎn)是不怕文件丟失.缺點(diǎn)是很容易被別人直接用資源修改工具打開修改.這個(gè)時(shí)候可以使用筆者寫的自制編程序工具PasAnywhere.不過這已經(jīng)是另外一個(gè)話題了. 

 
                         
                                
 
                                

 
                        
