C#调用Delphi的dll之详解

C#调用Delphi接口方法,有两种解决办法:

  一、将Delphi程序编译成一个COM组件,然后在C#里引用COM组件。

  二、非托管调用Dephi的DLL文件。

这里我们主要讲解一下第二种方法,讲第二种方法之前首先讲解下DllImport。

DllImport是System.Runtime.InteropServices命名空间下的一个属性类,其功能是提供从非托管DLL导出的函数的必要调用信息。

DllImport属性应用于方法,要求最少要提供包含入口点的dll的名称。
     DllImport的定义如下:

代码

1      [AttributeUsage(AttributeTargets.Method)]
 2      public class DllImportAttribute: System.Attribute
 3      {
 4       public DllImportAttribute(string dllName) {…} //定位参数为dllName
 5       public CallingConvention CallingConvention; //入口点调用约定
 6       public CharSet CharSet;                                   //入口点采用的字符接
 7       public string EntryPoint;                                  //入口点名称
 8       public bool ExactSpelling;                               //是否必须与指示的入口点拼写完全一致,默认false
 9       public bool PreserveSig;                                  //方法的签名是被保留还是被转换
10       public bool SetLastError;                                  //FindLastError方法的返回值保存在这里
11       public string Value { get {…} }
12      } 
13

  上面DLL的名字有时需要写上路径的如[DllImport(@"C:\OJ\Bin\Judge.dll")]这样指定DLL的绝对路径就可以正常装载。

假如没有路径的话,DllImport会按照顺序自动去寻找的地方: 
     1、exe所在目录 
     2、System32目录 
     3、环境变量目录
     所以只需要你把引用的DLL 拷贝到这三个目录下, 就可以不用写路径了。

说明:    
    1、DllImport只能放置在方法声明上。   
    2、DllImport具有单个定位参数:指定包含被导入方法的 dll 名称的 dllName 参数。   
    3、DllImport具有五个命名参数:    
        a、CallingConvention 参数指示入口点的调用约定。如果未指定 CallingConvention,则使用默认值 CallingConvention.Winapi。    
        b、CharSet 参数指示用在入口点中的字符集。如果未指定 CharSet,则使用默认值 CharSet.Auto。   
        c、EntryPoint 参数给出 dll 中入口点的名称。如果未指定 EntryPoint,则使用方法本身的名称。    
        d、ExactSpelling 参数指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配。如果未指定 ExactSpelling,则使用默认值 false。    
      e、PreserveSig 参数指示方法的签名应当被保留还是被转换。当签名被转换时,它被转换为一个具有 HRESULT返回值和该返回值的一个名为 retval 的附加输出参数的签名。如果未指定 PreserveSig,则使用默认值 true。    
      f、SetLastError 参数指示方法是否保留 Win32"上一错误"。如果未指定 SetLastError,则使用默认值 false。    
   4、它是一次性属性类。    
   5、此外,用 DllImport 属性修饰的方法必须具有 extern 修饰符。

下面讲解下如何调用:

用DllImport来调用的  一般是用非托管的。
  具体形式如下:1.[DllImport("WZFSE.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]。

  其中第一个参数是指要引用DLL的名字, 这个名字应该是个常量(否则会出错)。

要想在自己C#页面中引用,那就得在页面中申明这个函数。

  下面紧接着他的申明函数:
  2.public static extern void InitDll(IntPtr handle, bool methodAddress);(Dephi里怎么定义的函数在C#这里就要怎么定义:即Dephi的申明函数转换成C#的声明函数)。
  --申明一个函数就要引用下他的DLL 如1和2是紧密连在一起的。即再写一个函数就相应的应用起对应的DLL。

  下面是参数的引用:即Delphi的类型向C#的转换。

第一个参数类型:IntPtr这个类型可以申明为其他语言的句柄,指针等。
     若要实现其他语言类似C++的函数指针形式, 这时我们考虑用C#的委托来实现。

  

  下面说一下:如何将Dephi的窗体显示在自己的页面中(且不能显示Delphi窗体的标题栏,实现无缝的结合)。

  将dephi的窗体签入到自己的C#系统里 还有一点比较重要,我们是调用Delphi的窗体,此时显示在我们C#窗体中会有Delphi的窗体,

这时我们怎么办呢,  怎么去除Delphi中的窗体呢?  这时我们就需要用API函数了。 因为WINDOWS API是一种比较底层的语言,可以通过它进行操作。

在C#中是这么引用的: [DllImport("user32.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
                 public static extern void MoveWindow(IntPtr handler, int x, int y, int width, int height, bool repaint);

  下面插入一个类,这里面包含了怎么引用dephi的dll 以及怎么申明:

代码

1  public class CompliancePlatDLL
 2     {
 3         public static string strPath = "";
 4         /// <summary>
 5         /// 初始化
 6         /// </summary>
 7         /// <param name="handle"></param>
 8         /// <param name="methodAddress"></param>
 9         [DllImport("WZFSE.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
10         public static extern void InitDll(IntPtr handle, bool methodAddress);
11         /// <summary>
12         /// 加载相应的服务
13         /// </summary>
14         /// <param name="str"></param>
15         /// <param name="str2"></param>
16         /// <param name="i"></param>
17         /// <returns></returns>
18         [DllImport("WZFSE.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
19         public static extern IntPtr wzLoadModule(string str, string str2, int i);
20         /// <summary>
21         /// 去除相应的服务
22         /// </summary>
23         /// <param name="handle"></param>
24         /// <returns></returns>
25         [DllImport("WZFSE.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
26         public static extern bool wzUnloadModule(IntPtr handle);
27 
28         #region API函数
29         /// <summary>
30         /// API函数 设置主辅窗体
31         /// </summary>
32         /// <param name="child"></param>
33         /// <param name="parent"></param>
34         [DllImport("user32.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
35         public static extern void SetParent(IntPtr child, IntPtr parent);
36         /// <summary>
37         /// API函数 移动窗体
38         /// </summary>
39         /// <param name="handler"></param>
40         /// <param name="x"></param>
41         /// <param name="y"></param>
42         /// <param name="width"></param>
43         /// <param name="height"></param>
44         /// <param name="repaint"></param>
45         [DllImport("user32.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
46         public static extern void MoveWindow(IntPtr handler, int x, int y, int width, int height, bool repaint);
47 
48         [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
49         public static extern long GetWindowLong(IntPtr hwnd, int nIndex);
50         /// <summary>
51         /// API函数 去除窗体的标题栏
52         /// </summary>
53         /// <param name="hwnd"></param>
54         /// <param name="nIndex"></param>
55         /// <param name="dwNewLong"></param>
56         /// <returns></returns>
57         [DllImport("user32.dll", EntryPoint = "SetWindowLong")]
58         public static extern long SetWindowLong(IntPtr hwnd, int nIndex, long dwNewLong);
59         public const int GWL_EXSTYLE = -16;
60         public const int WS_EX_TRANSPARENT = 0x20;
61         public const int WS_EX_LAYERED = 0x80000;
62         public const int LWA_ALPHA = 2;
63         public const int WS_CAPTION = 0xC00000;
64         #endregion
65     }

其中API中的SetWindowLong这个方法是可以实现去除窗体的标题栏的,  具体调用SetWindowLong(common.p, GWL_EXSTYLE, GetWindowLong(handle, GWL_EXSTYLE) & (~WS_CAPTION));

  但一般完整利用API函数的调用是这样的

代码

1          decallback de1 = new decallback(iscallback);//利用委托
 2                InitDll(this.Handle, de1(this.Handle));//初始化
 3                IntPtr p = wzLoadModule("DoRiskSetup", "", 0);//取得句柄
 4                if (p != (IntPtr)0)//判断该句柄不是弹出窗体时
 5                {
 6                    //去除dephi窗体的标题栏
 7                    SetParent(p, panel1.Handle);
 8                    SetWindowLong(p, GWL_EXSTYLE, GetWindowLong(p, GWL_EXSTYLE) & (~WS_CAPTION));
 9                    MoveWindow(p, 0, 0, panel1.ClientSize.Width, panel1.ClientSize.Height, false);
10                }

   SetWindowLong(IntPtr handle, int t,long l) 第一个参数为句柄,是你调的dephi窗体的句柄,第二个参数为整型,在dephi用常量GWL_EXSTYLE表示,表示要显示的样式,在C#中翻译过来的他值为(-16),而第三个函则为长整型和第二个参数一起表示要去除第一个参数句柄窗体的标题栏在Delphi中表示为:GetWindowLong(handle,GWL_EXSTYLE) and (not WS_CAPTION) 在C#中则翻译为:GetWindowLong(handle,-16)&(~0xC00000),handle是指要调用的Delphi窗体的句柄,GetWindowLong这个函数是获得该窗体的相关信息。大体上是这个用法,如有不懂大家可以提出来 共同探讨。

一般类型对应如下:

  Dephi-->C#

  intger -->int

  longint -->long

  pchar -->string

  THandle -->IntPtr

时间: 2024-08-15 21:55:33

C#调用Delphi的dll之详解的相关文章

Java调用SMSLib发送短信详解

项目中需要用到发送短信功能,之前没做过这方面,找人咨询了一下,也网上查了查,发现并不是很复杂.目前项目已经完成了,做个记录以备后用.程序中发送短信主要有4种方法: 1.向当地的运营商申请网关,不需要额外的设备,利用对方提供的 API调用程序发送短信,适用于大型的通信公司.稳定,速度快,适合短信量特别大的需求,需要连接到运营商的网络中,不适合内网项目. 2.短信猫发送短信,借助像 GSM MODEM之类的设备(支持AT指令的手机也行),通过数据线连接电脑来发送短信,这种方法比较适用于小公司及个人.

&quot;静态方法里只能调用静态变量和静态方法&quot;详解

静态方法里可以调用静态方法和静态变量,同时也能调用非静态方法和非静态变量. public class Test { public Test() {}; public Test(int i) {this.n = i;} public static int m = 5; public int n = 10; public void fun1() {System.out.println("非静态方法fun1");} public static void fun2() {System.out.

php调用C代码的方法详解和zend_parse_parameters函数详解

http://blog.csdn.net/super_ufo/article/details/3863731 php调用C代码的方法详解 在php程序中需要用到C代码,应该是下面两种情况: 1 已有C代码,在php程序中想直接用 2 由于php的性能问题,需要用C来实现部分功能 针对第一种情况,最合适的方法是用system调用,把现有C代码写成一个独立的程序.参数通过命令行或者标准输入传入,结果从标准输出读出.其次,稍麻烦一点的方法是C代码写成一个daemon,php程序用socket来和它进行

c#(winform)环境下使用动态链接库dll的详解

1,什么是dll文件? DLL(Dynamic Link Library)文件为动态链接库文件,又称"应用程序拓展",是软件文件类型.在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中.当我们执行某一个程序时,相应的DLL文件就会被调用.一个应用程序可使用多个DLL文件,一个DLL文件也可能被不同的应用程序使用,这样的DLL文件被称为共享DLL文件. 2,托管dll和非托管dll区别是什么? 托管DLL就是能够在

vc调用delphi的dll 参数传递 报错

可能原因: 调用方式约定不一致. 函数调用约定如下: 1. __cdecl:C 和 C++ 程序的缺省调用规范. 2. __stdcall:标准调用约定(即WINAPI调用约定),也就是pascal调用约定. 如果VC调用时,调用的约定方式和delphi的dll中函数约定方式不一致,就会出问题.

c++DLL编程详解

DLL(Dynamic Link Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量.函数或类.在仓库的发展史上经历了“无库-静态链接库-动态链接库”的时代. 静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了.但是若使用DLL,该DLL不必被包含在最终EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件.静态链接库和动态链接库的另外一个区别在

Delphi常用关键字用法详解

absolute: ? 1 2 3 4 5 6 7 8 9 10 //它使得你能够创建一个新变量, 并且该变量的起始地址与另一个变量相同. var Str: string[32]; StrLen: Byte absoluteStr; //这个声明指定了变量StrLen起始地址与Str相同. //由于字符串的第0个位置保存了字符串的长度, 所以StrLen的值即字符串长度. begin Str := 'abc'; Edit1.Text := IntToStr(StrLen); end; abstr

delphi中ShellExecute使用详解

有三个API函数可以运行可执行文件WinExec.ShellExecute和CreateProcess. 1.CreateProcess因为使用复杂,比较少用. 2.WinExec主要运行EXE文件.如:WinExec('Notepad.exe Readme.txt', SW_SHOW); 3.ShellExecute不仅可以运行EXE文件,也可以运行已经关联的文件. 首先必须引用shellapi.pas单元:uses ShellAPI; 1).标准用法 ShellExecute函数原型及参数含

delphi 组件安装教程详解

学习安装组件的最好方法,就是自己编写一个组件并安装一遍,然后就真正明白其中的原理了. 本例,编写了两个BPL, dclSimpleEdit.bpl 与 SimpleLabel.bpl ,其中,dclSimpleEdit.bpl 依赖 SimpleLabel.bpl , 或者说 dclSimpleEdit.bpl 需要 SimpleLabel.bpl 才能运行.这也是多数组件安装问题之典型! 本例源码下载(delphi 7) 一.首先在delphi中打开 ComponentStudy 目录中的 C