作者:多米音乐_53913411 | 来源:互联网 | 2023-02-05 21:34
我需要编写一个DLL,但这是我第一次(总有一个),我找到了一个解决这个文档的解决方案.我最终得到了这段代码:
library DLLFrazioni;
uses
System.SysUtils,
System.Classes,
Fractions in 'Fractions.pas';
{$R *.res}
function getFraction(a: integer; b: integer): PChar; stdcall; overload;
var f: TFraction;
begin
f := TFraction.Create(a, b);
try
Result := PChar(f.getFraction);
except
Result := PChar('NaN');
end;
end;
function getFraction(a: PChar): PChar; stdcall; overload;
var f: TFraction;
begin
f := TFraction.Create(a);
try
Result := PChar(f.getFraction);
except
Result := PChar('NaN');
end;
end;
exports
getFraction(a: integer; b: integer),
getFraction(a: Pchar);
begin
end.
TFraction
在Fraction.pas中有一个类,它有这个实现(如果需要):
type
TFraction = class
private
number: double;
num, den: integer;
fraction: string;
function hcf(x: integer; y: integer): integer;
public
//input num+den -> result is a fraction num/den
constructor Create(numerator: integer; denominator: integer); overload;
//input string 'num/den' -> result is a reduced num/den
constructor Create(value: PChar); overload;
function getFraction: string;
end;
这里的一切都很简单.
我必须能够使用Delphi和C++(Visual Studio)加载这个DLL,但我怀疑我还没有用谷歌解决.正如你所看到的,我已经声明了另一个包含该类的单元,所以我可以将这两个东西分开.
我像往常一样在delphi DLL中使用stdcall.我有以下问题:
我必须创建一个object(f: TFraction
),因为我需要从中获取返回结果getFraction
.我是否必须使用通常的try-finally语句来包围它?我认为try-except更合适,因为我想在运行时避免异常.
如果我删除了try-except,当然会发生异常.在这种情况下,当我从Delphi/C++程序调用该函数时,我可以处理它.但这样安全吗?我可以允许dll引发异常吗?
Rob Kennedy..
5
一个except
块提供从一个完全不同的目的finally
块.这绝不是选择一个而不是另一个的问题.使用满足需求的任何一种.如果你需要两者,那么使用两者.一个except
块是用于处理错误.一个finally
块是为保护资源.
您对except
块的使用是正确的,以处理getFraction
失败的情况.
您应该包含一个finally
块来保护您分配的资源,即TFraction
对象.你现在根本没有释放对象,所以你有内存泄漏.
不允许异常转义DLL函数.你不能假设调用者知道如何处理抛出的Delphi对象.
编写DLL是一种情况,它对您有编写C和使用Windows API的经验非常有帮助.如果您编写的DLL遵循您在Windows API中看到的相同模式,那么您就是一个良好的基础.您会注意到Windows API函数从不引发异常.它们总是返回一个状态值,可能带有错误代码.
您的代码中还有其他问题.特别是,当你的DLL函数终止时,你将返回一个指向一个字符串的指针,因此指针是陈旧的.再次,遵循Windows API的模型是有帮助的.API几乎从不返回字符串.相反,API函数接收缓冲区指针和长度,然后填充调用者提供的缓冲区.返回字符串的API 通常使用记录的API分配内存,然后指定调用者稍后应使用哪种内存管理函数来释放内存.
在您的情况下,您将返回指向您未管理的内存的指针.编译器为您管理它,并且编译器无法看到您的函数的调用者仍然想要使用该内存,因此编译器会插入代码以释放您的字符串.
1> Rob Kennedy..:
一个except
块提供从一个完全不同的目的finally
块.这绝不是选择一个而不是另一个的问题.使用满足需求的任何一种.如果你需要两者,那么使用两者.一个except
块是用于处理错误.一个finally
块是为保护资源.
您对except
块的使用是正确的,以处理getFraction
失败的情况.
您应该包含一个finally
块来保护您分配的资源,即TFraction
对象.你现在根本没有释放对象,所以你有内存泄漏.
不允许异常转义DLL函数.你不能假设调用者知道如何处理抛出的Delphi对象.
编写DLL是一种情况,它对您有编写C和使用Windows API的经验非常有帮助.如果您编写的DLL遵循您在Windows API中看到的相同模式,那么您就是一个良好的基础.您会注意到Windows API函数从不引发异常.它们总是返回一个状态值,可能带有错误代码.
您的代码中还有其他问题.特别是,当你的DLL函数终止时,你将返回一个指向一个字符串的指针,因此指针是陈旧的.再次,遵循Windows API的模型是有帮助的.API几乎从不返回字符串.相反,API函数接收缓冲区指针和长度,然后填充调用者提供的缓冲区.返回字符串的API 通常使用记录的API分配内存,然后指定调用者稍后应使用哪种内存管理函数来释放内存.
在您的情况下,您将返回指向您未管理的内存的指针.编译器为您管理它,并且编译器无法看到您的函数的调用者仍然想要使用该内存,因此编译器会插入代码以释放您的字符串.