C#调用非托管DLL,窗口关闭后报错,求教!

_少年已不年_少 2015-12-03 03:58:32
这几天在做一个医院的报销接口系统,对方提供的接口是一个DLL动态库,暂且叫做A.DLL,是delphi的。其中A.DLL中封装的各功能方法,我都能正常调用,也都执行正常,但是唯一一点不足的就是,有的时候我关闭浏览器(我们的系统是BS)的时候,就会弹出下面的那个错误提示:无效的窗口句柄。
以前做此类报销接口的时候其他厂商也很多是非托管DLL,但是没有出现过此类情况。百度了很长时间,有的说资源释放问题,有的说是A.DLL自身没有做好处理,各种各样的方案吧。然后自己又写了一个CS的Demo来测试A.DLL,发现我调用完A.DLL中的某些方法成功,如果我直接关闭Demo.exe,也是会报下面图片上的错误:无效的窗口句柄。
实在是没有解决思路了,所以到万能的CSDN上找大家帮帮忙。虽然接口已经做好,不影响正常使用,但是每次关闭主程序的时候都会弹出这个错误,感觉还是不舒服。谢谢大家不吝指教。如果大家有解决方案尽量给出几句代码示例。或者稍微详细一些,因为本人现在实在不知道出现此问题的原因,也没什么解决思路。
唯一的一点思路,就是当我执行完A.DLL的方法的时候,能够将A.DLL进行释放。以及简单的代码示例,我将调用A.DLL中的各方法封装成一个IRCIANInterfaceHandle类,下面的代码中只封装了其中的一个方法当演示。

public class IRCIANInterfaceHandle
{
//A.DLL提供的获取就诊号
[DllImport("A.dll")]
private static extern int GetRecCode(StringBuilder strCode);

#region 联网获取就诊号
/// <summary>
/// 我的联网获取就诊号方法
/// </summary>
/// <returns></returns>
public string GetRegCode()
{
DataBuffers= new StringBuilder(5000);
//调用A.DLL的GetRecCode方法联网获取就诊号
int iRe = GetRecCode(DataBuffers);
if (iRe!=0)
{
LogManager.RecordException("联网获取医保就诊号失败!","N获取就诊号");
throw new Exception("联网获取医保就诊号失败!");
}
else
{
return DataBuffers.ToString();
}
}
#endregion
}






下面的代码就是,如果我的程序有需要去获取就诊号的话,我就去调用IRCIANInterfaceHandle类中的 GetRegCode方法,示例代码如下


private void TestMethod()
{
string MzCode="";
IRCIANInterfaceHandle iRsoft= new IRCIANInterfaceHandle();
MzCode=iRsoft.GetRegCode();
}


假如说我现在已经执行完获取就诊号这个方法,也获取成功了,我现在直接关闭我的程序,那就会报下面图片中的错误。

错误图片如下:


因为是自己为了说明问题,所以代码基本上就是为了说明思路手敲的,意思应该能说明白。
多谢各位!!在线等!
...全文
159 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
为了验证此问题,自己写了一个非常非常简单的Demo,就是一个按钮,调用A.DLL初始化的方法,初始化成功后,我直接关闭我的窗体,发现还是会报错。
  • 打赏
  • 举报
回复
引用 6 楼 ProgramFanA 的回复:
1、你Delphi中函数的导出类型是否跟你的调用约定一致; 2、将字符串参数作为指针传递,并在.NET中申请和释放内存试试: Marshal.AllocHGlobal Marshal.FreeHGlobal Marshal.StringToHGlobalAnsi Marshal.PtrToStringAnsi
我尝试下这种方法,不过工程量有点大。
  • 打赏
  • 举报
回复
引用 9 楼 ProgramFanA 的回复:
确实有可能,如果你关闭时这个API尚未返回,可以在方法最后面引用一下这个变量:GC.KeepAlive(DataBuffers)
你说的方案都已经尝试过,还是会报错,不过还是非常感谢。
wanbotang 2015-12-03
  • 打赏
  • 举报
回复
确实有可能,如果你关闭时这个API尚未返回,可以在方法最后面引用一下这个变量:GC.KeepAlive(DataBuffers)
  • 打赏
  • 举报
回复
引用 7 楼 wyd1520 的回复:
DataBuffers= new StringBuilder(5000); 原因是这个变量被回收了,而在C++的DLL里找不到这个变量的语句柄了。。。 你这个DataBuffers应是局部变量吧 全局就会被回收。。 public string GetRegCode() { StringBuilder DataBuffers= new StringBuilder(5000); 改成这样 //调用A.DLL的GetRecCode方法联网获取就诊号 int iRe = GetRecCode(DataBuffers); if (iRe!=0) { LogManager.RecordException("联网获取医保就诊号失败!","N获取就诊号"); throw new Exception("联网获取医保就诊号失败!"); } else { return DataBuffers.ToString(); } }
我赶快尝试一下
本拉灯 2015-12-03
  • 打赏
  • 举报
回复
DataBuffers= new StringBuilder(5000); 原因是这个变量被回收了,而在C++的DLL里找不到这个变量的语句柄了。。。 你这个DataBuffers应是局部变量吧 全局就会被回收。。 public string GetRegCode() { StringBuilder DataBuffers= new StringBuilder(5000); 改成这样 //调用A.DLL的GetRecCode方法联网获取就诊号 int iRe = GetRecCode(DataBuffers); if (iRe!=0) { LogManager.RecordException("联网获取医保就诊号失败!","N获取就诊号"); throw new Exception("联网获取医保就诊号失败!"); } else { return DataBuffers.ToString(); } }
wanbotang 2015-12-03
  • 打赏
  • 举报
回复
1、你Delphi中函数的导出类型是否跟你的调用约定一致; 2、将字符串参数作为指针传递,并在.NET中申请和释放内存试试: Marshal.AllocHGlobal Marshal.FreeHGlobal Marshal.StringToHGlobalAnsi Marshal.PtrToStringAnsi
  • 打赏
  • 举报
回复
在线继续等各位
  • 打赏
  • 举报
回复
我将交互方法写成Modle.dll,在Modle.dll中封装跟第三方交互的方法,并且在这个Modle.dll中引用非托管的第三方DLL,也就是A.DLL
  • 打赏
  • 举报
回复
引用 2 楼 bdmh 的回复:
你是不是有后台线程,在不停的调用这个接口呢,关闭时,接口释放,如果有线程再访问,就会出错
我们的系统有独立的一套接口框架,有自己的接口规范,专门应对各种医保厂商,我首先是会根据我们系统的接口规范去编写一个类库比如说是Modle.DLL,此动态库继承了我们系统的父类,我会在Modle继承的方法中去调用医保厂商的联网方法,也就是A.DLL中的联网获取就诊号的方法。 说白了,就是我们系统通过浏览器找到我指定文件夹下的Modle.dll,通过这个动态库去跟医保厂商尽心光交互。
bdmh 2015-12-03
  • 打赏
  • 举报
回复
你是不是有后台线程,在不停的调用这个接口呢,关闭时,接口释放,如果有线程再访问,就会出错
  • 打赏
  • 举报
回复
在线等待各位的回复,多谢!

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧