Gu.*_*u. 4 delphi dll overloading
德尔福Xe.
在模块Windows.pas中,我看到一种方法:
function InterlockedExchangeAdd(Addend: PLongint; Value: Longint): Longint stdcall; overload;
{$EXTERNALSYM InterlockedExchangeAdd}
function InterlockedExchangeAdd(var Addend: Longint; Value: Longint): Longint stdcall; overload;
{$EXTERNALSYM InterlockedExchangeAdd}
...
function InterlockedExchangeAdd(Addend: PLongint; Value: Longint): Longint; external kernel32 name 'InterlockedExchangeAdd';
function InterlockedExchangeAdd(var Addend: Longint; Value: Longint): Longint; external kernel32 name 'InterlockedExchangeAdd';
Run Code Online (Sandbox Code Playgroud)
意味着,DLL可以导出具有相同名称的函数.
我试着重复一遍:
我创建了这个项目
Program TestMyDll;
{$APPTYPE CONSOLE}
uses SimpleShareMem, SysUtils;
Function MyFunc(const X:Integer):string; StdCall; External 'MyDll.dll' Name 'MyFunc'; Overload;
Function MyFunc(const X:Extended):string; StdCall; External 'MyDll.dll' Name 'MyFunc'; Overload;
begin
try
Writeln;
Writeln('MyDll test');
Writeln('Int: ' + MyFunc(10));
Writeln('Real: ' + MyFunc(10.55));
Readln;
except on E: Exception do Writeln(E.ClassName, ' : ', E.Message);end;
end.
Run Code Online (Sandbox Code Playgroud)
它正常编译.我进一步创建DLL:
Library MyDll;
uses
SimpleShareMem,
DllUnit1 in 'DllUnit1.pas';
{$R *.res}
begin
//test
MyFunc(10);MyFunc(10.55);
end.
Run Code Online (Sandbox Code Playgroud)
......和模块DllUnit1.pas
Unit DllUnit1; Interface
Function MyFunc(const X:Integer):string; Overload; StdCall;
Function MyFunc(const X: Extended):string; Overload; StdCall;
Exports
MyFunc; // COMPILE ERROR
Implementation
Uses SysUtils;
Function MyFunc(const X:Integer):string;
begin
result:=Inttostr(x);
end;
Function MyFunc(const X: Extended):string;
begin
result:=Floattostr(x);
end;
end.
Run Code Online (Sandbox Code Playgroud)
但在编译时我收到一个错误:[DCC错误] DllUnit1.pas(7):E2273没有带有此参数列表的'MyFunc'的重载版本存在.
在Delphi帮助中,我看到:
"Delphi Language Reference"/"The exports clause"
...
When you export an overloaded function or procedure from a dynamically loadable library, you must specify its parameter list in the exports clause. For example,
exports
Divide(X, Y: Integer) name 'Divide_Ints',
Divide(X, Y: Real) name 'Divide_Reals';
On Windows, do not include index specifiers in entries for overloaded routines.
Run Code Online (Sandbox Code Playgroud)
问题:
如何在模块DllUnit1中导出这些函数是否正确,以及是否可以在Delphi(一个名称下导出)中一般地使用它从我的项目TestMyDll开始接收相同的调用(例如来自windows.pas)?
如果可以使用一个名称导出这些函数,那么通过调用其他语言的DLL(VB,C++)来处理它是否正确?或者最好使用不同的名称制作两个函数?
PS这里有点类似的问题(http://stackoverflow.com/questions/6257013/how-to-combine-overload-and-stdcall-in-delphi),但答案不适合我
PSS英语不好
ADD(已在答案后添加)
显然,谢谢.
已经这样做了:
在项目中:
Function MyFunc (const X:Integer):string; StdCall; External 'MyDll.dll' Name 'MyFunc'; Overload;
Function MyFunc (const X:Extended):string; StdCall; External 'MyDll.dll' Name ' MyFunc1'; Overload;
Run Code Online (Sandbox Code Playgroud)
在DllUnit1中
Exports
MyFunc (const X:Integer) Name 'MyFunc',
MyFunc (const X:Extended) Name 'MyFunc1';
Run Code Online (Sandbox Code Playgroud)
它编译并正常工作.
还是问题:
喜欢作品,但它是否正确?
是否有值如何写"Function MyFunc(const X:Integer):string; Overload; StdCall;" 或"函数MyFunc(const X:Integer):string; StdCall; Overload;"?
这个函数在其他语言的项目(Vb,C++,C#)中会被正确引起吗?
Rem*_*eau 11
意味着,DLL可以导出具有相同名称的函数.
不,不是的.Delphi InterlockedExchangeAdd()
使用不同的参数声明2个重载,但kernel32.dll只导出一个InterlockedExchangeAdd()
函数.两个Delphi声明正在导入相同的DLL函数.在运行时调用函数时,重载参数是等效的.换句话说,就功能而言Addend: PLongint
,var Addend: Longint
它们是相同的.在运行时,它们都是指向a的指针Longint
.
第一个声明使用C风格的语法Addend
通过显式指针传递参数:
var
Value, Ret: Longint;
begin
Ret := InterlockedExchangeAdd(@Value, 1);
end;
Run Code Online (Sandbox Code Playgroud)
第二个声明使用Delphi风格的语法来通过Addend
引用传递参数:
var
Value, Ret: Longint;
begin
Ret := InterlockedExchangeAdd(Value, 1);
end;
Run Code Online (Sandbox Code Playgroud)
从动态可加载库中导出重载函数或过程时,必须在exports子句中指定其参数列表.
我从来没有在我的DLL中那样做,但是我也从不导出重载.指定参数允许编译器区分哪个导出使用哪个重载,但是如示例所示,这些重载由不同的名称导出,尽管它们在DLL的编码中使用相同的名称.
最好使用不同的名称制作两个函数?**
是.
DLL按名称和序数值导出函数.每个都必须是独一无二的.您不能导出具有相同名称或相同序号的两个不同函数.
您的示例InterlockedExchangeAdd
仅仅是两个具有不同但等效签名的函数,这些函数引用相同的函数.这样做是为了方便呼叫者.
让我们把序数留在一边,专注于名字.从上面的第一段可以清楚地看出,你必须为每个函数使用不同的名称.当然,您仍然可以在内部使用重载,但指定不同的名称作为exports子句的一部分.同样,在导入时,您可以声明导入的函数是重载,但使用name语法指定DLL名称.
因此,总而言之,您可以轻松地在接口的两侧内部使用重载,但在导出和导入函数时必须使用唯一的名称.这是一个简单的例子:
导出功能的库
library liba;
procedure F(X: Integer); stdcall; overload;
begin
end;
procedure F(X, Y: Integer); stdcall; overload;
begin
end;
exports
F(X: Integer) name 'F1',
F(X, Y: Integer) name 'F2';
begin
end.
Run Code Online (Sandbox Code Playgroud)
导入功能的库
library libb;
procedure F(X: Integer); stdcall; overload; external 'liba.dll' name 'F1';
procedure F(X, Y: Integer); stdcall; overload; external 'liba.dll' name 'F2';
begin
end.
Run Code Online (Sandbox Code Playgroud)
该overload
关键字可以在声明中任何地方出现.它出现在哪里并不重要.另一方面,调用约定必须出现在之前external
.
请注意,不支持重载的语言(即VB6,C)显然无法导入函数并为它们使用相同的名称.同样,对于不支持在导入时重命名函数的语言(即C++).据我所知,只有Delphi才能在导入时允许这样的巧妙技巧.
对于支持重载的C++和C#等语言,您需要引入另一层间接.例如在C#中你会这样做:
[DllImport("liba.dll")]
private static extern void F1(int X);
[DllImport("liba.dll")]
private static extern void F2(int X, int Y);
public static void F(int X)
{
F1(X);
}
public static void F(int X, int Y)
{
F2(X, Y);
}
Run Code Online (Sandbox Code Playgroud)
在C++中可以使用完全相同的方法.这种方法与我上面展示的Delphi代码之间唯一真正的区别是Delphi语言支持直接语法来实现这种映射.
关于你的问题中的各种例子,这些都使用字符串当然是私有的Delphi类型.string
如果要从Delphi以外的任何语言调用该函数,则不得在导出函数中使用.或者实际上除了你用DLL构建DLL之外的任何编译器版本.
归档时间: |
|
查看次数: |
6074 次 |
最近记录: |