程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 在Delphi編程中使用C語言代碼

在Delphi編程中使用C語言代碼

編輯:Delphi

Windows下編程的工具有很多,例如VB,Delphi,VC等等.我在這裡不想討論"它們的具體哪個更好一點"這種幼稚的問題.玩過DOS程序設計的人都知道,DOS下很多語言的實質核心還是調用系統提供的匯編中斷函數.到了Windows下,它就變成了我們常說的API了.而在Windows下寫程序很多時候都是調用API,語言,只不過是一個表達工具而已.

我現在已經參加工作大約有半年左右,我們公司是用Borland公司的Delphi作為主開發工具.本著未偏袒任何一個工具的立場,我說句公道話:Delphi是目前Win32下開發程序的最快速,最有效率的工具.

Delphi適合用來開發應用程序,但是有時侯一些底層的東西可以直接使用C語言來開發.我在公司經常開發跟硬件相關的項目,而很多硬件的SDK包是用C來寫的.這個時候我一般把它們轉換成Delphi(PASCAL)語法的代碼.下面談一下我的個人粗淺經驗.因為當時學校教的是Pascal語言,所以我對C語言並不是太熟手.下面的觀點或者代碼如有錯漏之處希望高手們放小弟一馬:)

一:將C語言的程序編譯成DLL供Delphi調用.這種方法過於簡單,而且需要額外帶一個DLL文件,所以不在本文的討論范圍之內.

二:直接轉換C語言代碼到DELPHI代碼

C語言的函數格式與Delphi不同,它們是函數返回類型在前,函數聲明在後.對於沒有任何返回類型的函數則定義為VOID類型.

例如:Delphi中函數function MyFunction:(intIN:integer):Bool;相應的C語言代碼就變成Bool MyFunction(int intIN);又例如procedure MyProcedure;====>void MyProcedure;采用這種方法,一般要求對C語言比較熟悉.我一般是采用這種方法.下面是我收集整理的自己常用的Delphi與C之間的類型對應表.其中左邊是C類型,右邊是對應的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
  LONGDOUBLE->Extended
  LONGINT->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
  SHORTINT->SmallInt
  SIZE->TSize
  TEXTMETRIC->TTextMetric
  TPOINT->TPoint
  TRECT->TRect
  TTPOLYCURVE->TTTPolyCurve
  TTPOLYGONHEADER->TPolygonHeader
  UINT->Word
  UNSIGNED->Word
  UNSIGNEDCHAR->Byte
  UNSIGNEDINT->Word
  UNSIGNEDLONG->LongInt(DWORD)
  UNSIGNEDLONGINT->LongInt
  UNSIGNEDSHORT->Word
  UNSIGNEDSHORTINT->Word
  VOID*->Pointer
  WINDOWPLACEMENT->TWindowPlacement
  WINDOWPOS->TWindowPos
  WNDCLASS->TWndClass
  WORD->Word

三:在Delphi中直接鏈接C語言的OBJ文件.

這種方法的好處在於最終EXE不用帶任何外部文件.也不用對C語言過於熟悉.

我們都知道,代碼在編譯成可執行文件(或DLL,OCX文件,下同)之前,都必須得先生成OBJ文件(DELPHI一般是DCU文件,但也可以通過編輯編譯選項生成OBJ文件),然後把OBJ文件和資源文件(*.RES)鏈接成最終的可執行文件.利用這個方法,我們可以直接把OBJ文件鏈接到我們的程序裡面.

不過需要注意的是,編譯器不同,生成的OBJ文件也不一樣.Microsoft的編譯器生成的OBJ文件是COFF格式,而Borland的C++Builder生成的是OMF格式.因為我們需要在Delphi中鏈接,所以必須使用CBC,或者Borland官方站點帶的免費編譯工具.下面我們通過一個簡單的例子來說明具體操作步驟:

這個例子是簡單的提供一個函數,用來判斷一個文件是否為Dat格式的VCD文件.頭文件聲明如下:

以下是引用片段:
  /*
  文件名稱:DatFormat.h
  */
  #ifndefDatFormat_H
  #defineDatFormat_H
  #include 
  #pragmapack(push,1)//這個與下面的配對,一般用到記錄類型的時候需要定義,這裡實際不用
  #ifdef__cplusplus
  extern"C"{
  #endif
  externBOOLCheckIsDatFile(constchar*FileName,BOOL*IsDatFile);
  #ifdef__cplusplus
  }
  #endif
  #pragmapack(pop)
  #endif//DatFormat_H
  具體實現代碼DatFormat.c如下:
  #include"DatFormat.h"
  BOOLCheckIsDatFile(constchar*FileName,BOOL*IsDatFile)
  /*
  函數說明:該函數用於判斷一個文件是否為Dat文件(即VCD文件)格式.
  參數:
  IN:
  FileName:欲判斷的文件名稱
  IN,OUT:
  IsDatFile:是否為Dat格式文件
  OUT:
  讀文件失敗返回FALSE,否則返回TRUE.
  ------------------------------------
  作者:陳經韬.2004,01,17.http://www.138soft.com,[email protected]
  */
  {
  HANDLEhFile;
  DWORDdwBytesRead;
  BOOLre;
  charMyBuf[4];
  *IsDatFile=FALSE;
  //建立讀文件句柄
  hFile=CreateFile(FileName,
  GENERIC_READ,
  FILE_SHARE_READ,
  NULL,
  OPEN_EXISTING,
  0,
  0);
  if(hFile==INVALID_HANDLE_VALUE)returnFALSE;
  //讀文件
  re=ReadFile(hFile,
  &MyBuf,
  4,
  &dwBytesRead,
  NULL);
  if(dwBytesRead!=4)
  {
  CloseHandle(hFile);
  returnFALSE;
  }
  //讀文件失敗的時候
  if(re!=TRUE)
  {
  CloseHandle(hFile);
  returnFALSE;
  }
  CloseHandle(hFile);
  *IsDatFile=(MyBuf[0]=='R'&&MyBuf[1]=='I'&&MyBuf[2]=='F'&&MyBuf[3]=='F');
  return(TRUE);
  }

運行CBC,新建一個工程,然後把DatFormat.c添加到工程裡面,編譯整個工程,將得到我們需要的OBJ文件:DatFormat.OBJ.然後我們關閉CBC即可,因為下面不再需要用到它了.

運行Delphi,新建一個工程並保存.然後把DatFormat.OBJ拷貝到它的目錄之下.在單元的implementation下面添加如下代碼:

{$LINK 'DatFormat.obj'} //鏈接外部OBJ文件

function _CheckIsDatFile(const FileName:Pchar;IsDatFile:PBool):Bool;cdecl;external;//定義函數.其中cdecl進棧方式說明采用C語言格式傳遞參數.external說明是個外部聲明函數.

注意函數聲明的原形與C定義的不一樣.必須在前面添加一個下劃線.原因是因為編譯器的鏈接符號中.C與C++是不一樣的.因為這個不是本文重點,所以這裡不作討論.請感興趣的朋友自行參閱相關資料.

然後我們寫如下代碼調用此函數:

以下是引用片段:
  procedureTFrmMain.Button1Click(Sender:TObject);
  var
  IsDatFile:Bool;
  begin
  ifOpenDialog1.Executethen
  if_CheckIsDatFile(Pchar(OpenDialog1.FileName),@IsDatFile)then
  ifIsDatFilethenShowMessage('恭喜!該文件是一個Dat格式的視頻文件!')
  elseShowMessage('不好意思,該文件不是一個Dat格式的視頻文件!')
  elseShowMessage('讀文件錯誤!');
  end;

編譯這個程序,將得到一個干淨的可執行EXE文件了.

四:C++Builder中使用Delphi單元

這個實際是題外話了,不過這裡還是提一提:假設我們有一個獲取BIOS密碼的Delphi單元

unit AwardBiosPas;

{=======================================================

項目: 在Delphi編程中使用C語言代碼- 演示程序

模塊: 獲取BIOS密碼單元

描述:

版本:

日期: 2004-01-17

作者: 陳經韬[email protected],http://www.138soft.com

更新: 2004-01-17

=======================================================}

以下是引用片段:
  interface
  uses
  windows,SysUtils;
  functionMy_GetBiosPassword:string;
  implementation
  functionCalcPossiblePassword(PasswordValue:WORD):string;
  var
  I:BYTE;
  C:CHAR;
  S:string[8];
  begin
  I:=0;
  whilePasswordValue<>0do
  begin
  Inc(I);
  if$263>PasswordValuethen
  begin
  if$80>PasswordValuethen
  S[I]:=CHAR(PasswordValue)
  elseif$B0>PasswordValuethen
  S[I]:=CHAR(PasswordValueand$77)
  elseif$11D>PasswordValuethen
  S[I]:=CHAR($30or(PasswordValueand$0F))
  elseif$114>PasswordValuethen
  begin
  S[I]:=CHAR($64or(PasswordValueand$0F));
  if'0'>S[I]then
  S[I]:=CHAR(BYTE(S[I])+8);
  end
  elseif$1C2>PasswordValuethen
  S[I]:=CHAR($70or(PasswordValueand$03))
  elseif$1E4>PasswordValuethen
  S[I]:=CHAR($30or(PasswordValueand$03))
  else
  begin
  S[I]:=CHAR($70or(PasswordValueand$0F));
  if'z'<S[I]then
  S[I]:=CHAR(BYTE(S[I])-8);
  end;
  end
  else
  S[I]:=CHAR($30or(PasswordValueand$3));
  PasswordValue:=(PasswordValue-BYTE(S[I]))shr2;
  end;
  S[0]:=CHAR(I);
  PasswordValue:=Ishr1;
  whilePasswordValue<Ido
  begin{thisistodobecauseawardstartscalculatingwiththelastletter}
  C:=S[BYTE(S[0])-I+1];
  S[BYTE(S[0])-I+1]:=S[I];
  S[I]:=C;
  Dec(I);
  end;
  CalcPossiblePassword:=S;
  end;
  functionreadcmos(off:byte):byte;
  var
  value:byte;
  begin
  asm
  xorax,ax
  moval,off
  out70h,al
  inal,71h
  movvalue,al
  end;
  readcmos:=value;
  end;
  functionMy_GetBiosPassword:string;
  var
  superpw,userpw:word;
  begin
  ifWin32Platform<>VER_PLATFORM_WIN32_NTthen//不是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+'超級用戶密碼為:'+CalcPossiblePassword(superpw)+#13+'用戶密碼為:'+CalcPossiblePassword(userpw);
  end
  else
  Result:='用戶系統為NT,無法獲取BIOS密碼!';
  end;
  end.

如何直接在CBC中使用它呢?新建一個CBC工程,然後把這個單元加到項目裡面去.具體操作為:Add to Project--->文件類型:pascal unit(*.pas),然後Build Demo1.這個時候將在AwardBiosPas.pas的同目錄下生成一個AwardBiosPas.hpp文件.把它引用到我們的需要調用的單元.然後直接調用即可:

以下是引用片段:
  void__fastcallTFrmMain::Button1Click(TObject*Sender)
  {
  ShowMessage(My_GetBiosPassword());
  }

五:其它方法.當然可以用RES將C語言生成的二進制文件,但這個方法與第一種方法差不多.優點是不怕文件丟失.缺點是很容易被別人直接用資源修改工具打開修改.這個時候可以使用筆者寫的自制編程序工具PasAnywhere.不過這已經是另外一個話題了.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved