我不止一次建议人们使用类型的返回值WideString进行互操作.
这个想法是a WideString和a一样BSTR.因为a BSTR是在共享COM堆上分配的,所以在一个模块中分配并在另一个模块中解除分配是没有问题的.这是因为所有各方都同意使用相同的堆,即COM堆.
但是,它似乎WideString不能用作互操作的函数返回值.
考虑以下Delphi DLL.
library WideStringTest;
uses
ActiveX;
function TestWideString: WideString; stdcall;
begin
Result := 'TestWideString';
end;
function TestBSTR: TBstr; stdcall;
begin
Result := SysAllocString('TestBSTR');
end;
procedure TestWideStringOutParam(out str: WideString); stdcall;
begin
str := 'TestWideStringOutParam';
end;
exports
TestWideString, TestBSTR, TestWideStringOutParam;
begin
end.
Run Code Online (Sandbox Code Playgroud)
和以下C++代码:
typedef BSTR (__stdcall *Func)();
typedef void (__stdcall *OutParam)(BSTR &pstr);
HMODULE lib = LoadLibrary(DLLNAME);
Func TestWideString = (Func) GetProcAddress(lib, "TestWideString"); …Run Code Online (Sandbox Code Playgroud) 我有一个用Delphi编写的dll和测试应用程序.测试应用程序使用多个线程来调用dll导出的函数.导出的函数具有简单的线程安全实现.运行测试应用程序时会发生各种错误(访问冲突,无效指针操作,堆栈溢出等)或应用程序冻结.在某些情况下,应用程序完成没有错误.
请注意,这些错误仅在使用多个线程时发生(表面).从主线程调用函数时,一切正常.
我发现将ShareMem添加到dll和应用程序会停止所有这些错误.但我不明白为什么.据我所知,只有在dll和应用程序之间传递长字符串时才需要ShareMem.据我所知,WideString不是一个长字符串.
另外根据这篇文章,不应该要求ShareMem: 为什么Delphi DLL可以在不使用ShareMem的情况下使用WideString?
这是dll的来源:
library External;
uses
Winapi.Windows;
type
TMyType = class
private
FText: string;
end;
function DoSomething(input: WideString; out output: WideString): Bool; stdcall;
var
x: TObject;
begin
x := TMyType.Create;
try
output := x.ClassName;
finally
x.Free;
end;
Result := True;
end;
exports
DoSomething;
begin
end.
Run Code Online (Sandbox Code Playgroud)
这是测试应用程序:
program ConsoleTest;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
Winapi.Windows,
OtlParallel;
function DoSomething(input: WideString; out output: WideString): Bool; stdcall; external 'External.dll' name 'DoSomething';
var
sResult: WideString;
begin
try
Parallel.&For(0, 500).Execute(procedure(value: Integer)
var
sResult: …Run Code Online (Sandbox Code Playgroud) 如果我不返回任何内容,则工作正常,或者返回一个整数.但如果我试图返回一个PChar,即...
result := PChar('') or result:= PChar('Hello')
Run Code Online (Sandbox Code Playgroud)
网络应用程序只是冻结,我看着它的内存数量在任务管理器中逐渐变得越来越高.
奇怪的是,DLL在VStudio调试服务器或C#应用程序上运行良好.我唯一能想到的就是IIS服务器在64位Windows上运行.
它似乎不是一个兼容性问题,因为我可以成功写入文本文件并从DLL中执行其他操作...我只是不能返回一个PChar字符串.
尝试使用PWideChar,尝试返回'something\0',尝试了我能想到的一切.不幸的是没有运气.
[DllImport("TheLib.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
private static extern string SomeFunction();
string result = SomeFunction();
Run Code Online (Sandbox Code Playgroud)
德尔福:
library TheLib;
function SomeFunction() : PChar export; stdcall;
begin
return PChar('');
end;
exports
SomeFunction
Run Code Online (Sandbox Code Playgroud) 我有一个C#DLL,它使用Unmanaged Exports公开一个函数,它由Inno Setup Pascal脚本直接调用.此函数需要将字符串返回给Inno Setup.我的问题是如何实现这一目标?
我首选的方法是将Inno Setup中的缓冲区传递给C#函数,该函数将返回此缓冲区内的字符串.我想出了这段代码:
C#功能:
[DllExport("Test", CallingConvention = CallingConvention.StdCall)]
static int Test([Out, MarshalAs(UnmanagedType.LPWStr)] out string strout)
{
strout = "teststr";
return strout.Length;
}
Run Code Online (Sandbox Code Playgroud)
Inno安装脚本:
function Test(var res: String):Integer; external 'Test@files:testdll.dll stdcall';
procedure test1;
var
Res: String;
l: Integer;
begin
SetLength(Res,256);
l := Test(Res);
{ Uncommenting the following line causes an exception }
{ SetLength(Res,l); }
Log('"Res"');
end;
Run Code Online (Sandbox Code Playgroud)
当我运行此代码时,Res变量为空(我在日志中看到"")
如何从此DLL返回一个字符串?
请注意,我使用的是Inno Setup的Unicode版本.我也不想使用COM调用此函数,也不想在DLL中分配缓冲区并将其返回给Inno Setup.
这将是我第一次尝试在Delphi中编写DLL以从其他语言调用.
我已经做了很多谷歌搜索并看到一些好的指针,但没有详尽无遗(至少,我有问题,在Embarcadero材料中没有找到答案).
我想知道这个警告列表是否有效,或者我是否遗漏了什么,如果有人可以在下面提出我的问题.
ShareMem单位.String类型,应该坚持下去PCharintegetr和PChar其他人一样)的简单类型吗?几个问题:
integers和PChars 的长参数列表? 布尔值?或者我坚持"zer0 ===假,其他一切都是真的"?
还有什么我应该知道的吗?
在此先感谢您的帮助