最近很多小伙伴都在问vb.net调用Delphidll问题和vb调用dll实例这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展(Delphi)使用函数指针参数调用DLL、.net调
最近很多小伙伴都在问vb.net 调用Delphi dll问题和vb调用dll实例这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展(Delphi)使用函数指针参数调用DLL、.net 调用delphi 的DLL、C# 调用 Delphi DLL、C# 调用delphi编写的dll等相关知识,下面开始了哦!
本文目录一览:- vb.net 调用Delphi dll问题(vb调用dll实例)
- (Delphi)使用函数指针参数调用DLL
- .net 调用delphi 的DLL
- C# 调用 Delphi DLL
- C# 调用delphi编写的dll
vb.net 调用Delphi dll问题(vb调用dll实例)
前一段项目,要调用第三方的接口实现医保卡读取和医保信息上传.遇到一个太诡异的问题.
不管怎么调用使用显示"出错误尝试读取或写入受保护的内存。这通常指示其他内存已损坏。" 问题.
对于Delphi中的Pchar 类型的 使用(Byval StringBuilder…定义
如:
Public Shared Function Test(ByVal p As StringBuilder,ByRef d As Single) As Integer
End Function
Public Shared Function Freadcard(ByVal iprescno As Integer,ByVal Icardtype As Integer,……
这样Delphi 对 stringBuilder 的值改变才能被取出来. 这样避免乱码的问题.
(Delphi)使用函数指针参数调用DLL
我最近有一些不同的问题,传递一些参数到DLL,你帮助.
希望,有人知道如何做到这一点….
这是DLL(cpp)中需要从Delphi调用的函数声明:
typedef void (*PTR_Allocate)(char**,unsigned long*); typedef void (*PTR_Deallocate)(char*); extern "C" export_dll_function void SetAllocateFunction(PTR_Allocate); extern "C" export_dll_function void SetDeallocateFunction(PTR_Deallocate); void Allocate(char** pbuffer,unsigned long* psize) { *psize = *psize * 2; *pbuffer = new char[*psize]; } void Deallocate(char* buffer) { delete[] buffer; }
能帮助我在Delphi(7)中重写这个吗?
这是我尝试过的,它抛出一个异常(“外部异常”):
type PByte = ^TByte; TByte = array of byte; TFunc = function(var pbuffer: PByte; var psize: Cardinal): integer; cdecl; Procedure _SetAllocateFunction(var f: TFunc); cdecl; implementation function Allocate(var pbuffer: PByte; var psize: Cardinal): Integer; cdecl; begin psize := psize * 2; GetMem(pbuffer,psize); end; var Func: TFunc; Func := @Allocate; _SetAllocateFunction(Func);
非常感谢你 !
解决方法
type PTR_Allocate = procedure(param1: ^^Char; param2: ^LongWord); cdecl;
一旦你确定它是正确的,那么就开始用更多类似Delphi的东西替换它们.如果你跳过这第一步,你可能永远无法做到正确,因为你只会继续改变错误的东西.
所以,你确定以上是对的吗?不完全的. Delphi中的Char可能具有不同的含义,具体取决于产品版本.您正在使用Delphi 7,但您可能会升级,因此您可能会与其他人共享此代码,因此您应该明确您想要的Char大小.需要单字节类型时使用AnsiChar.
type PTR_Allocate = procedure(param1: ^^AnsiChar; param2: ^LongWord); cdecl;
现在我们可以开始让它看起来更像Delphi.一级指针参数可以用“var”或“out”指令替换.对每个参数执行此操作:
type PTR_Allocate = procedure(out param1: ^AnsiChar; var param2: LongWord); cdecl;
Pointer-to-AnsiChar是一种常见的类型,Delphi已经为它命名了:PAnsiChar.使用惯用名:
type PTR_Allocate = procedure(out param1: PAnsiChar; var param2: LongWord); cdecl;
最后,你可能希望对整个概念采取一些自由,即完全涉及角色.你明确地为任意字节缓冲区分配内存,所以Byte可能是比任何字符类型更好的选择.最近的Delphi版本声明了一个指向字节的指针类型,所以使用:
type PTR_Allocate = procedure(out param1: PByte; var param2: LongWord); cdecl;
现在开始使用SetAllocateFunction.它表示它接收一个PTR_Allocate参数,该参数是一个指向函数的指针. Delphi的过程类型是隐式指针,因此我们上面声明的类型已经完全适合Delphi等价.不要通过引用传递额外的“var”指令,否则即使在程序尝试分配任何内存之前,您也会遇到问题.这是其他答案忽略的问题.
procedure SetAllocateFunction(param: PTR_Allocate); cdecl;
不要在名称的开头添加下划线,除非您想要调用自己的代码不方便.如果它是使用不同的名称从DLL导出的,那么在编写函数的实现时使用“name”子句:
procedure SetAllocateFunction; extern 'foo.dll' name '_SetAllocateFunction';
最后,如何实现分配功能.从匹配PTR_Allocate签名的内容开始,然后继续使用原始C代码中的尽可能翻译实现它.
procedure Allocate(out pbuffer: PByte; var psize: LongWord; cdecl; begin psize := psize * 2; GetMem(pbuffer,psize); end;
您可以使用之前的功能进行设置:
SetAllocateFunction(Allocate);
注意我不需要单独的变量,我没有使用@运算符.如果你需要使用@运算符来提及函数指针,在大多数情况下,你做错了.你通常不需要它.使用该运算符可以隐藏程序中的错误,例如签名不匹配,因为默认设置是@运算符无类型.使用它从函数指针中删除类型,并且无类型指针与Delphi中的所有内容兼容,因此它们适用于任何其他函数指针类型,包括具有错误签名的类型.
当编译器已经指示它已经尝试调用该函数时,仅在函数指针上使用@,例如通过提及您没有足够的参数或提及函数的返回类型.
.net 调用delphi 的DLL
总结
以上是小编为你收集整理的.net 调用delphi 的DLL全部内容。
如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。
C# 调用 Delphi DLL
l
技术实现
如何逐步实现动态库的加载,类型的匹配,动态链接库函数导出的定义,参考下面宏定义即可:
#define LIBEXPORT_API extern "C" __declspec(dllexport)
第一步,我先从简单的调用出发,定义了一个简单的函数,该函数仅仅实现一个整数加法求和:
LIBEXPORT_API int mySum(int a,int b){ return a+b;}
C# 导入定义:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
public static extern int mySum (int a,int b);
}
在C#中调用测试:
int iSum = RefComm.mySum(,);
运行查看结果iSum为5,调用正确。第一步试验完成,说明在C#中能够调用自定义的动态链接库函数。
第二步,我定义了字符串操作的函数(简单起见,还是采用前面的函数名),返回结果为字符串:
LIBEXPORT_API char *mySum(char *a,char *b){sprintf(b,"%s",a); return a;}
C# 导入定义:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Auto,
CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, string b);
}
在C#中调用测试:
string strDest="";
string strTmp= RefComm.mySum("45", strDest);
运行查看结果 strTmp 为"45",但是strDest为空。我修改动态链接库实现,返回结果为串b:
LIBEXPORT_API char *mySum(char *a,char *b){sprintf(b,"%s",a) return b;}
修改 C# 导入定义,将串b修改为ref方式:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, ref string b);
}
在C#中再调用测试:
string strDest="";
string strTmp= RefComm.mySum("45", ref strDest);
运行查看结果 strTmp 和 strDest 均不对,含不可见字符。再修改 C# 导入定义,将CharSet从Auto修改为Ansi:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, string b);
}
在C#中再调用测试:
string strDest="";
string strTmp= RefComm. mySum("45", ref strDest);
运行查看结果 strTmp 为"45",但是串 strDest 没有赋值。第二步实现函数返回串,但是在函数出口参数中没能进行输出。再次修改 C# 导入定义,将串b修改为引用(ref):
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, ref string b);
}
运行时调用失败,不能继续执行。
第三步,修改动态链接库实现,将b修改为双重指针:
LIBEXPORT_API char *mySum(char *a,char **b){sprintf((*b),"%s",a); return *b;}
C#导入定义:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, ref string b);
}
在C#中调用测试:
string strDest="";
string strTmp= RefComm. mySum("45", ref strDest);
运行查看结果 strTmp 和 strDest 均为"45",调用正确。第三步实现了函数出口参数正确输出结果。
第四步,修改动态链接库实现,实现整数参数的输出:
LIBEXPORT_API int mySum(int a,int b,int *c){ *c=a+b; return *c;}
C#导入的定义:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
public static extern int mySum (int a, int b,ref int c);
}
在C#中调用测试:
int c=0;
int iSum= RefComm. mySum(,, ref c);
运行查看结果iSum 和c均为5,调用正确。
经过以上几个步骤的试验,基本掌握了如何定义动态库函数以及如何在 C# 定义导入,有此基础,很快我实现了变长加密函数在 C# 中的调用,至此目标实现。
三、结论
在 C# 中调用 C++ 编写的动态链接库函数,如果需要出口参数输出,则需要使用指针,对于字符串,则需要使用双重指针,对于 C# 的导入定义,则需要使用引用(ref)定义。
对于函数返回值,C# 导入定义和 C++ 动态库函数声明定义需要保持一致,否则会出现函数调用失败。定义导入时,一定注意 CharSet 和 CallingConvention 参数,否则导致调用失败或结果异常。运行时,动态链接库放在 C# 程序的目录下即可,我这里是一个 C# 的动态链接库,两个动态链接库就在同一个目录下运行。
C# 调用delphi编写的dll
技术实现
如何逐步实现动态库的加载,类型的匹配,动态链接库函数导出的定义,参考下面宏定义即可:
#define LIBEXPORT_API extern "C" __declspec(dllexport)
第一步,我先从简单的调用出发,定义了一个简单的函数,该函数仅仅实现一个整数加法求和:
LIBEXPORT_API int mySum(int a,int b){ return a+b;}
C# 导入定义:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
public static extern int mySum (int a,int b);
}
在C#中调用测试:
int iSum = RefComm.mySum(,);
运行查看结果iSum为5,调用正确。第一步试验完成,说明在C#中能够调用自定义的动态链接库函数。
第二步,我定义了字符串操作的函数(简单起见,还是采用前面的函数名),返回结果为字符串:
LIBEXPORT_API char *mySum(char *a,char *b){sprintf(b,"%s",a); return a;}
C# 导入定义:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Auto,
CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, string b);
}
在C#中调用测试:
string strDest="";
string strTmp= RefComm.mySum("45", strDest);
运行查看结果 strTmp 为"45",但是strDest为空。我修改动态链接库实现,返回结果为串b:
LIBEXPORT_API char *mySum(char *a,char *b){sprintf(b,"%s",a) return b;}
修改 C# 导入定义,将串b修改为ref方式:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, ref string b);
}
在C#中再调用测试:
string strDest="";
string strTmp= RefComm.mySum("45", ref strDest);
运行查看结果 strTmp 和 strDest 均不对,含不可见字符。再修改 C# 导入定义,将CharSet从Auto修改为Ansi:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, string b);
}
在C#中再调用测试:
string strDest="";
string strTmp= RefComm. mySum("45", ref strDest);
运行查看结果 strTmp 为"45",但是串 strDest 没有赋值。第二步实现函数返回串,但是在函数出口参数中没能进行输出。再次修改 C# 导入定义,将串b修改为引用(ref):
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, ref string b);
}
运行时调用失败,不能继续执行。
第三步,修改动态链接库实现,将b修改为双重指针:
LIBEXPORT_API char *mySum(char *a,char **b){sprintf((*b),"%s",a); return *b;}
C#导入定义:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, ref string b);
}
在C#中调用测试:
string strDest="";
string strTmp= RefComm. mySum("45", ref strDest);
运行查看结果 strTmp 和 strDest 均为"45",调用正确。第三步实现了函数出口参数正确输出结果。
第四步,修改动态链接库实现,实现整数参数的输出:
LIBEXPORT_API int mySum(int a,int b,int *c){ *c=a+b; return *c;}
C#导入的定义:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
public static extern int mySum (int a, int b,ref int c);
}
在C#中调用测试:
int c=0;
int iSum= RefComm. mySum(,, ref c);
运行查看结果iSum 和c均为5,调用正确。
经过以上几个步骤的试验,基本掌握了如何定义动态库函数以及如何在 C# 定义导入,有此基础,很快我实现了变长加密函数在 C# 中的调用,至此目标实现。
三、结论
在 C# 中调用 C++ 编写的动态链接库函数,如果需要出口参数输出,则需要使用指针,对于字符串,则需要使用双重指针,对于 C# 的导入定义,则需要使用引用(ref)定义。
对于函数返回值,C# 导入定义和 C++ 动态库函数声明定义需要保持一致,否则会出现函数调用失败。定义导入时,一定注意 CharSet 和 CallingConvention 参数,否则导致调用失败或结果异常。运行时,动态链接库放在 C# 程序的目录下即可,我这里是一个 C# 的动态链接库,两个动态链接库就在同一个目录下运行。
我们今天的关于vb.net 调用Delphi dll问题和vb调用dll实例的分享就到这里,谢谢您的阅读,如果想了解更多关于(Delphi)使用函数指针参数调用DLL、.net 调用delphi 的DLL、C# 调用 Delphi DLL、C# 调用delphi编写的dll的相关信息,可以在本站进行搜索。
本文标签: