16,748
社区成员
发帖
与我相关
我的任务
分享
procedure TfrmDesignReport.btnDesignClick(Sender: TObject);
var
hDll: THandle;
ShowForm: function(IPAddress, CommandText, Paramstr: WideString;
var RetString: WideString): boolean; StdCall;
RetString: WideString;
xmlStr: WideString;
begin
xmlStr := '<Report><报表ID>' + IntToStr(edtTemplateName.Tag) + '</报表ID></Report>';
RetString := '';
hDll := LoadLibrary(PWideChar(ExtractFilePath(Application.ExeName) +
'\ReportDesign.dll'));
if hDll < 32 then
Exit; // 如果Dll无法加载则跳出
@ReportSetForm := GetProcAddress(hDll, 'ShowForm');
if @ReportSetForm = nil then
begin
MessageBox(GetActiveWindow, '调用报表设计失败!', '系统提示', 48);
FreeLibrary(hDll);
Exit;
end;
try
ShowForm(ServerAddress, '报表设计', xmlStr, RetString)
finally
FreeLibrary(hDll);
end;
end;
/// <summary>
/// 加载程序集并调用里面的方法,在调用完成之后自动释放
/// </summary>
/// <param name="fileName">程序集文件名称</param>
/// <param name="funtionName">函数名称</param>
/// <param name="methodDelegate">委托类型(与原函数保持一致)</param>
/// <param name="customeRun">自定义运行委托</param>
/// <param name="message">消息</param>
protected virtual void doLoadAndCall(string fileName, string funtionName, Type methodDelegate, Action<Delegate> customeRun, SimpleMessager message)
{
IntPtr address = IntPtr.Zero;
message.Success = false;
try
{
try
{
address = UnsafeNativeMethods.LoadLibrary(fileName);
}
catch (Exception exp)
{
EventLogger.AddLogger(exp);
throw new Exception(string.Format("加载程序集失败!原因:[{0}]", exp.Message));
}
if (address == IntPtr.Zero)
{
message.AddMessage(GetCurrentSystemErrorMessage());
return;
}
IntPtr methodHandle = Win32Native.GetProcAddress(address, funtionName);
Delegate myDelegate = null;
Marshal.GetDelegateForFunctionPointer(methodHandle, methodDelegate);
customeRun(myDelegate);
message.Success = true;
}
catch (Exception exp)
{
message.AddMessage(exp.Message);
EventLogger.AddLogger(exp);
}
finally
{
if (address != null)
{
UnsafeNativeMethods.FreeLibrary(address);
}
}
}
delegate bool ShowFormDelegate(string serverAddres, string formTitle, string xmlString, string returnString);
string localFile = @"ReportDesign.dll";
if (!File.Exists(localFile))
{
MessageBox.Show(localFile);
}
doLoadAndCall("ReportDesign.dll", "ShowForm", typeof(ShowFormDelegate), (Delegate x) =>
{
}, message);
if (!message.Success)
{
MessageBox.Show(message.Message);
}
/*
在选则编译器输出为X64或AnyCPU时报
ErrorCode:193
Message:%1不是有效的Win32应用程序
在选则编译器输出为X86时程序直接退出
*/
[DllImport(@"ReportDesign.dll",SetLastError = true)]
internal static extern bool ShowForm(string serverAddres, string formTitle, string xmlString, string returnString);
ShowForm("http://127.0.0.1/GDZCLocalDataSqlServer/", "报表设计", xmlConfig, returnValue);
/*
在选则编译器输出为X64或AnyCPU时报
System.BadImageFormatException:试图加载格式不正确的程序。(异常来自HRESULT:0X8007000B)
在选则编译器输出为X86时程序直接退出
*/
//输出正确
[DllImport(@"Hello_Delphi.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
internal static extern Char* Hello_WideString_PChar([MarshalAs(UnmanagedType.BStr)]string name);
//Unicode I2 StdCall name:string-LPWStr 传入name='一',输出空
//Unicode I2 StdCall name:StringBuilder-LPWStr 内存错误
//Unicode I2 StdCall name:string-BStr 传入name='一二三',输出'二'
[DllImport(@"Hello_Delphi.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.I2)]
internal static extern Char Hello_String_WideChar([MarshalAs(UnmanagedType.BStr)]string name);
试过传入PChar、WideString等数据类型,只要返回的不是string或WideString都没问题。
将返回值改成String或WideString后将传入参数值ShowMessage出来显示空。然后程序就报 "尝试读取或写入受保护的内存"错误。
//无法调用,不管使用什么CallingConvention都报"调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配"
Function Hello_Null_WideString():WideString ;stdcall;
begin
Result:='Hello,Mr X.';
end;
//name始终为空,ShowMessage后,C#取值总是报"尝试读取或写入受保护的内存"
Function Hello_WideString_WideString(name: WideString):WideString ;stdcall;
begin
ShowMessage(name);
Result:= 'Hello,'+name;
end;
//正常
Function Hello_WideString_PChar(name: WideString):PChar ;stdcall;
begin
ShowMessage(name);
Result:=PChar( 'Hello,'+name);
end;
void TestLoadDelphiDll()
{
{
string response = null;
try
{
StringBuilder builder = new StringBuilder();
//response = Hello_Int_Int(0).ToString(); //1
//response = Hello_String_Int("一二三").ToString(); //123
//response = Hello_String_String("ABCDE"); //尝试读取或写入受保护的内存
//builder = Hello_String_String1("AAA"); //尝试读取或写入受保护的内存
//response = builder.ToString();
//response = Hello_String_WideChar("一二三").ToString(); //z
//response = Hello_String_WideChar("123456").ToString(); //2
//response = Hello_String_Char("123456").ToString(); //2
//response = Hello_String_Char("一二三").ToString(); //?
//response = new string(Hello_String_PChar("123456")); //Hello,123456
response = new string(Hello_String_PChar("一二三")); //Hello,一二三
}
catch (Exception exp)
{
response = exp.Message;
}
MessageBox.Show(response);
Application.Current.Shutdown();
}
}
[DllImport(@"Hello_Delphi.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
internal static extern int Hello_Int_Int(int name);
[DllImport(@"Hello_Delphi.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
internal static extern int Hello_String_Int([MarshalAs(UnmanagedType.LPWStr)]string name);
[DllImport(@"Hello_Delphi.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.LPWStr)]
internal static extern string Hello_String_String([MarshalAs(UnmanagedType.LPWStr)]string name);
[DllImport(@"Hello_Delphi.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "Hello_String_String")]
[return: MarshalAs(UnmanagedType.LPWStr)]
internal static extern StringBuilder Hello_String_String1([MarshalAs(UnmanagedType.LPWStr)]string name);
[DllImport(@"Hello_Delphi.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "Hello_String_WideChar")]
internal static extern Char Hello_String_WideChar([MarshalAs(UnmanagedType.LPWStr)]string name);
[DllImport(@"Hello_Delphi.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "Hello_String_Char")]
internal static extern Char Hello_String_Char([MarshalAs(UnmanagedType.LPWStr)]string name);
[DllImport(@"Hello_Delphi.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "Hello_String_PChar")]
internal static extern Char* Hello_String_PChar([MarshalAs(UnmanagedType.LPWStr)]string name);
uses
System.SysUtils,
System.Classes;
Function Hello_String_WideChar(name:WideString):WideChar ;stdcall;
begin
if(Length( name)>2)Then
BEGIN
Result:= name[2]; //使用name[0]无法通过编译:
//[dcc32 Error] Hello_Delphi.dpr(11): E2157 Element 0 inaccessible - use 'Length' or 'SetLength'
END else
BEGIN
Result:='空';
END;
end;
Function Hello_String_Char(name:String):Char ;stdcall;
begin
if(name.Length>1)Then
BEGIN
Result:= name.Chars[1];
END else
BEGIN
Result:='空';
END;
end;
Function Hello_String_PChar(name:String):PChar ;stdcall;
begin
name:='Hello,'+name;
Result:=PChar( name);
end;
Function Hello_String_String(name:String):String ;stdcall;
begin
Result:='Hello,'+name;
end;
Function Hello_String_Int(name:WideString):longint ;stdcall;
begin
Result:=123;
end;
Function Hello_Int_Int(name:longint):longint ;stdcall;
begin
Result:=name+1;
end;
exports Hello_String_WideChar, Hello_String_Char, Hello_String_PChar,
Hello_String_String, Hello_String_Int, Hello_Int_Int;
begin
end.
由此可见C# 调用返回WideString、String 类型的Dephi Dll 应该是数据格式错了。
错误应用程序名称: GDZC.Client_WPF.exe,版本: 1.0.0.0,时间戳: 0x55b63091
错误模块名称: Test_Delphi_Hello.dll,版本: 0.0.0.0,时间戳: 0x2a425e19
异常代码: 0xc0000005
错误偏移量: 0x00004633
错误进程 ID: 0x42a0
错误应用程序启动时间: 0x01d0c86f4d2711cf
错误应用程序路径: D:\XDQ\GDZC.CS\Code\GDZC.Client\bin\Debug\GDZC.Client_WPF.exe
错误模块路径: D:\XDQ\GDZC.CS\Code\GDZC.Client\bin\Debug\Test_Delphi_Hello.dll
报告 ID: 8b37b6f9-3462-11e5-8385-80fa5b0be0cd
错误程序包全名:
错误程序包相对应用程序 ID:
Window错误报告:
源
GDZC.Client
摘要
已停止工作
日期
2015/7/27 21:22
状态
未报告
描述
错误的应用程序路径: D:\XDQ\GDZC.CS\Code\GDZC.Client\bin\Debug\GDZC.Client_WPF.exe
问题签名
问题事件名称: APPCRASH
应用程序名: GDZC.Client_WPF.exe
应用程序版本: 1.0.0.0
应用程序时间戳: 55b6306b
故障模块名称: KERNELBASE.dll
故障模块版本: 6.3.9600.17415
故障模块时间戳: 54504ade
异常代码: c000041d
异常偏移: 00014598
OS 版本: 6.3.9600.2.0.0.256.48
区域设置 ID: 2052
其他信息 1: 4f2e
其他信息 2: 4f2ec231c3a5452c8bfcf3a48093385a
其他信息 3: eed2
其他信息 4: eed248bd83187b7fc7ffca16bceeb4d6
/*
编译器:Delphi7
编译环境:Windows Xp
*/
library Hello_Delphi;
uses
SysUtils,
Classes;
Function Hello(name:WideString) : WideString;stdcall;
begin
Result :='Hello , '+name;
end;
exports Hello;
begin
end.
/*
编译器:Vs2013
编译环境:Windows 8.1 X64
编译输出:X86
开发框架:WPF
*/
void TestLoadDelphiDll()
{
SimpleMessager message = new SimpleMessager();
WindowsHelper.LoadAndCall("Test_Delphi_Hello.dll", "Hello", typeof(HelloDelegate), (x) =>
{
HelloDelegate hello = x as HelloDelegate;
string response = null;
try
{
response = x.DynamicInvoke(new Object[] { "哈哈" }) as string;
}
catch (Exception exp)
{
response = exp.Message;
}
MessageBox.Show(response);
}, message);
if (!message.Success)
{
MessageBox.Show(message.Message);
}
{
string response = null;
try
{
response = Hello("呵呵");
}
catch (Exception exp)
{
response = exp.Message;
}
MessageBox.Show(response);
}
}
delegate string HelloDelegate(string name);