我刚刚调试了一个函数,它返回一个让我担心的字符串.我一直认为返回字符串的函数的隐式Result变量在函数调用开始时将为空,但以下(简化)代码产生了意外的结果:
function TMyObject.GenerateInfo: string;
procedure AppendInfo(const AppendStr: string);
begin
if(Result > '') then
Result := Result + #13;
Result := Result + AppendStr;
end;
begin
if(ACondition) then
AppendInfo('Some Text');
end;
Run Code Online (Sandbox Code Playgroud)
多次调用此函数导致:
"Some Text"
Run Code Online (Sandbox Code Playgroud)
第一次,
"Some Text"
"Some Text"
Run Code Online (Sandbox Code Playgroud)
第二次,
"Some Text"
"Some Text"
"Some Text"
Run Code Online (Sandbox Code Playgroud)
第三次等
要修复它,我必须初始化结果:
begin
Result := '';
if(ACondition) then
AppendInfo('Some Text');
end;
Run Code Online (Sandbox Code Playgroud)
是否需要初始化字符串函数结果?为什么(技术上)?为什么编译器不会发出警告"W1035函数的返回值'xxx'可能是未定义的"字符串函数?我是否需要遍历所有代码以确保设置值,因为如果未明确设置结果,则期望函数中的空字符串不可靠?
我在一个新的测试应用程序中对此进行了测试,结果是一样的.
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
S: string;
begin
for i := 1 to 5 do
S := GenerateInfo;
ShowMessage(S); // 5 …Run Code Online (Sandbox Code Playgroud) David对另一个问题的回答显示Delphi DLL函数返回一个WideString.我从没想过如果没有使用它是可能的ShareMem.
我的测试DLL:
function SomeFunction1: Widestring; stdcall;
begin
Result := 'Hello';
end;
function SomeFunction2(var OutVar: Widestring): BOOL; stdcall;
begin
OutVar := 'Hello';
Result := True;
end;
Run Code Online (Sandbox Code Playgroud)
我的来电计划:
function SomeFunction1: WideString; stdcall; external 'Test.dll';
function SomeFunction2(var OutVar: Widestring): BOOL; stdcall; external 'Test.dll';
procedure TForm1.Button1Click(Sender: TObject);
var
W: WideString;
begin
ShowMessage(SomeFunction1);
SomeFunction2(W);
ShowMessage(W);
end;
Run Code Online (Sandbox Code Playgroud)
它有效,我不明白怎么做.我所知道的约定是Windows API使用的约定,例如Windows GetClassNameW:
function GetClassNameW(hWnd: HWND; lpClassName: PWideChar; nMaxCount: Integer): Integer; stdcall;
Run Code Online (Sandbox Code Playgroud)
意味着调用者提供缓冲区和最大长度.Windows DLL以长度限制写入该缓冲区.调用者分配和释放内存.
另一种选择是DLL分配内存,例如通过使用LocalAlloc,并且调用者通过调用释放内存LocalFree.
内存分配和解除分配如何与我的DLL示例一起使用?"魔法"是否会发生,因为结果是WideString(BSTR …
Delphi应用程序如何调用导出的函数(非COM)dotNET程序集并让函数返回一个字符串?
COM不是我的特定应用程序的可能解决方案.我控制了通话的两端.
type
TStrProc = procedure( var x: widestring); stdcall;
function TryIt: string;
var
Handle: THandle;
Proc: TStrProc;
InData: widestring;
OutData: widestring;
begin
Handle := LoadLibrary( 'DelphiToDotNet.dll');
if Handle = 0 then exit;
@Proc := GetProcAddress( Handle, 'StrProc');
if @Proc <> nil then
begin
InData := 'input';
Proc( InData);
OutData := InData;
end;
FreeLibrary( Handle);
result := OutData
end;
Run Code Online (Sandbox Code Playgroud)
public class DotNetDllClass
{
[DllExport]
public static string StrProc(ref string s)
{
return "Hello from .Net …Run Code Online (Sandbox Code Playgroud) 我正在尝试编译一个64位的dll,用于64位C#应用程序.我有一个简单的类和一个简单的应用程序来尝试和测试它,它无论我尝试做什么都会失败.这是代码:
德尔福
library project1;
{$mode objfpc}{$H+}
uses
Classes;
function Encrypt(aName:PChar):PChar;stdcall;
begin
Result := aName;
end;
exports Encrypt;
begin
end.
Run Code Online (Sandbox Code Playgroud)
C#
[DllImport("project1.dll")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern String Encrypt([MarshalAs(UnmanagedType.LPStr)] String aName);
Run Code Online (Sandbox Code Playgroud)
任何人都可以看到它有什么问题,如果没有花哨创造同样的简单场景试图让这个工作,我就在我的系绳的尽头!
我有一个用Delphi(未知版本)编写的第三方"神秘dll",在delphi(2009年)中的工作示例,急需在我的C#代码中使用所述dll,并且几乎没有关于如何执行它的相关知识.
以下是使用此dll的Delpi示例:
type
TD_Query = function(host: WideString; port : Word;pud,query : WideString):WideString; stdcall;
procedure TForm11.Button6Click(Sender: TObject);
var
Handle : LongWord;
D_Query : TD_Query;
sss : WideString;
begin
Handle := LoadLibrary('kobrasdk.dll');
sss:='';
if Handle <> 0 then
begin
@D_Query := GetProcAddress(Handle, 'D_Query');
sss:=D_Query('host',8201,'pud','query');
FreeLibrary(Handle);
end;
end;
Run Code Online (Sandbox Code Playgroud)
这是我尝试用C#解释它:
class Program
{
[DllImport("C:\\Games\\kobrasdk.dll", CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string D_Query(string host, ushort port, string pud, string query);
static void Main(string[] args)
{
D_Query("test", 8201, "test", "test");
} …Run Code Online (Sandbox Code Playgroud) 我试图使用以下签名调用Delphi DLL中的方法:
function SMap4Ovr(const OverFileName : ShortString ;
const Aclay : Integer ;
const Acarbon : Double ;
out errstr : ShortString): WordBool;
Run Code Online (Sandbox Code Playgroud)
我在C#中使用以下导入:
[DllImport("SMap.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern bool SMap4Ovr(
string OverFileName,
int Aclay,
double Acarbon,
out string errstr
);
Run Code Online (Sandbox Code Playgroud)
但我得到一个AccessViolationException.
我似乎能够调用DLL中的几个更简单的方法,这些方法有字符串参数但不是int或double.
我也试过CallingConvention = CallingConvention.Cdecl,但这给了我同样的错误.
我一直在学习将非托管DLL导入编组到C#中...而且我遇到了一些我不太了解的东西.
在Delphi中,有一个函数Result := NewStr(PChar(somestring))从a 返回Procedure SomeFunc() : PChar; Stdcall;
根据我的理解,NewStr只在本地堆上分配一个缓冲区...而SomeFunc正在返回一个指向它的指针.
在.NET 4.0(客户端配置文件)中,通过C#我可以使用:
[DllImport("SomeDelphi.dll", EntryPoint = "SomeFunc", CallingConvention = CallingConvention.StdCall)]
public static extern String SomeFunc(uint ObjID);
Run Code Online (Sandbox Code Playgroud)
这在Windows 7 .NET 4.0 Client Profile中很有效(或者正如David所说,"似乎工作").在Windows 8中,它具有不可预测的行为,这使我走上了这条道路.
所以我决定在.NET 4.5中尝试相同的代码并获得Heap损坏错误.好的,现在我知道这不是正确的做事方式.所以我进一步挖掘:
仍在.NET 4.5中
[DllImport("SomeDelphi.dll", EntryPoint = "SomeFunc", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr _SomeFunc();
public static String SomeFunc()
{
IntPtr pstr = _SomeFunc();
return Marshal.PtrToStringAnsi(pstr);
}
Run Code Online (Sandbox Code Playgroud)
这没有任何障碍.我(新手)担心的是NewStr()已经分配了这个内存,它只是永远坐在那里.我的担忧无效吗?
在.NET 4.0中,我甚至可以这样做,它永远不会抛出异常:
[DllImport("SomeDelphi.dll", EntryPoint = "SomeFunc", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr _SomeFunc();
public static …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) // delphi代码(delphi版本:Turbo Delphi Explorer(它是Delphi 2006))
function GetLoginResult:PChar;
begin
result:=PChar(LoginResult);
end;
Run Code Online (Sandbox Code Playgroud)
//使用上面的delphi函数的C#代码(我使用的是unity3d,在C#中)
[DllImport ("ServerTool")]
private static extern string GetLoginResult(); // this does not work (make crash unity editor)
[DllImport ("ServerTool")]
[MarshalAs(UnmanagedType.LPStr)] private static extern string GetLoginResult(); // this also occur errors
Run Code Online (Sandbox Code Playgroud)
在C#中使用该功能的正确方法是什么?
(也用于delphi,代码就像if(event = 1)和(tag = 10)then writeln('Login result:',GetLoginResult);)
我已经导入了dll.所有其他部分都有效,但导入方法的字符串返回值给出:
***.exe中0x7748EA5F(ntdll.dll)的未处理异常:0xC0000374:堆已损坏(参数:0x774C4270).
它仍然返回字符串,但我担心这会导致其他一些错误,这很难调试.根据我的测试结果,感觉它可以是任何东西,这就是造成这种情况的原因.
这是我的导入代码:
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
private delegate String GetStringDelegate(int handle, int index);
private static GetStringDelegate getString { get; set; }
var addressOfGetString = NativeMethods.GetProcAddress(_handle, "GetString");
getString = (GetStringDelegate)Marshal.GetDelegateForFunctionPointer(addressOfGetString, typeof(GetStringDelegate));
Run Code Online (Sandbox Code Playgroud)
用法
getString(Handle, 1);
Run Code Online (Sandbox Code Playgroud)
这有效,但它会导致错误.在调试时,只需按"继续"将允许它处理它并显示结果.结果是对的.
这是在delphi dll中完成的
function GetString(Hnd,Index : Integer) : PChar; stdcall;
begin
Result:=TControl(Hnd).Stack.GetString(Index);
end;
Run Code Online (Sandbox Code Playgroud)
我有相同类型的整数,双精度,bool和dll中的其他所有代码,没有错误.所以我认为它会产生一些溢出或错误的内存分配大小.
注意:如果我创建控制台应用程序,它只是失败,没有中断错误,如果我运行没有调试器的控制台(ctrl + f5),它工作,仍然没有错误.当我从表单应用程序调用它时生成堆错误.
TL; DR; 这段代码有效,但它显示了堆错误,而返回int,bools等工作完美.
delphi ×10
c# ×8
pinvoke ×3
dllimport ×2
interop ×2
.net ×1
delphi-2007 ×1
dll ×1
freepascal ×1
iis ×1
lazarus ×1
widestring ×1