点击这里给我发消息 点击这里给我发消息

在Delphi编程中使用C语言代码

添加时间:2013-12-7
    相关阅读: 设计 开发 程序 Windows DW AI 链接
副标题#e#
  在Delphi编程中使用C语言代码
 
  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
  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

 

#p#副标题#e#

 

  三:在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
  */
  #ifndef DatFormat_H
  #define DatFormat_H
  #include
  #pragma pack(push, 1)//这个与下面的配对,一般用到记录类型的时候需要定义,这里实际不用
  #ifdef __cplusplus
  extern "C" {
  #endif
  extern BOOL CheckIsDatFile(const char * FileName,BOOL *IsDatFile);
  #ifdef __cplusplus
  }
  #endif
  #pragma pack(pop)
  #endif // DatFormat_H
  具体实现代码DatFormat.c如下:
  #include "DatFormat.h"
  BOOL CheckIsDatFile(const char * FileName,BOOL *IsDatFile)
  /*
  函数说明:该函数用于判断一个文件是否为Dat文件(即VCD文件)格式.
  参数:
  IN:
  FileName:欲判断的文件名称
  IN,OUT:
  IsDatFile:是否为Dat格式文件
  OUT:
  读文件失败返回FALSE,否则返回TRUE.
  ------------------------------------
  作者:陈经韬.2004,01,17. http://www.138soft.com,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;
  }
  //读文件失败的时候
  if (re!=TRUE)
  {
  CloseHandle(hFile);
  return FALSE;
  }
  CloseHandle(hFile);
  *IsDatFile=(MyBuf[0]=='R' && MyBuf[1]=='I' && MyBuf[2]=='F' && MyBuf[3]=='F');
  return(TRUE);
  }

#p#副标题#e#

  运行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++是不一样的。因为这个不是本文重点,所以这里不作讨论。请感兴趣的朋友自行参阅相关资料。
 
  然后我们写如下代码调用此函数:

 以下是引用片段:
  procedure TFrmMain.Button1Click(Sender: TObject);
  var
  IsDatFile:Bool;
  begin
  if OpenDialog1.Execute then
  if _CheckIsDatFile(Pchar(OpenDialog1.FileName),@IsDatFile) then
  if IsDatFile then ShowMessage('恭喜!该文件是一个Dat格式的视频文件!')
  else ShowMessage('不好意思,该文件不是一个Dat格式的视频文件!')
  else ShowMessage('读文件错误!');
  end;


  编译这个程序,将得到一个干净的可执行EXE文件了。

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

  这个实际是题外话了,不过这里还是提一提:假设我们有一个获取BIOS密码的Delphi单元

  unit AwardBiosPas;

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

  项目: 在Delphi编程中使用C语言代码- 演示程序

  模块: 获取BIOS密码单元

  描述:

  版本:

  日期: 2004-01-17

  作者: 陈经韬.lovejingtao@21cn.com,http://www.138soft.com

  更新: 2004-01-17

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

#p#副标题#e#

 

 以下是引用片段:
  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+'超级用户密码为:' + 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 __fastcall TFrmMain::Button1Click(TObject *Sender)
  {
  ShowMessage(My_GetBiosPassword());
  }


  五:其它方法。

    当然可以用RES将C语言生成的二进制文件,但这个方法与第一种方法差不多。优点是不怕文件丢失。缺点是很容易被别人直接用资源修改工具打开修改。这个时候可以使用笔者写的自制编程序工具PasAnywhere.不过这已经是另外一个话题了。
 

 

相关在Delphi编程中使用C语言代码

咨询热线:020-85648757 85648755 85648616 0755-27912581 客服:020-85648756 0755-27912581 业务传真:020-32579052
广州市网景网络科技有限公司 Copyright◎2003-2008 Veelink.com. All Rights Reserved.
广州商务地址:广东省广州市黄埔大道中203号(海景园区)海景花园C栋501室
= 深圳商务地址:深圳市宝源路华丰宝源大厦606
研发中心:广东广州市天河软件园海景园区 粤ICP备05103322号 工商注册