前言:调用dll时,需要先问清楚dll是由什么语言编译的,要不然方向错了会有很多无用功
试错过程:
直接引用出错:“…不是规范的COM组件”DllImportm方式
[DllImport("yhinterface.dll", EntryPoint = "f_sblwsk", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]public static extern void f_sblwsk(string hospitalComb, ref object ret);
更详细的可见c#调用外部dll
使用以上方法遇到的报错
直接引用时,报错“尝试写入或读取受保护的内存,这通常是指内存已损坏”DllImport时,报错无法找到方法入口无法加载该模块
解决方案思路:
最开始由于不知道dll是pb生成的,误当作c++生成的,所以当报错无法找到入口时,就怀疑提供方给错dll了,当时接口文档也没有说清楚,就一直在找这个问题。后来注册了该dll,把相关的依赖项放进与exe同级目录下,就可以直接引用进去了之后直接调用的时候,需要new一个对象,用过两种方式 常见new
COClass_n_yhinterface b = new COClass_n_yhinterface();
反射
```csharpprivate object Invoke(string lpFileName, string Namespace, string ClassName, string lpProcName, object[] ObjArray_Parameter){try{// 载入程序集Assembly MyAssembly = Assembly.LoadFrom(lpFileName);Type[] type = MyAssembly.GetTypes();foreach (Type t in type){// 查找要调用的命名空间及类if (t.Namespace == Namespace && t.Name == ClassName){// 查找要调用的方法并进行调用MethodInfo m = t.GetMethod(lpProcName);if (m != null){object o = Activator.CreateInstance(t);return m.Invoke(o, ObjArray_Parameter);}else Console.WriteLine(" 装载出错 !");}}}catch (System.NullReferenceException e){Console.WriteLine(e.Message);}//catchreturn (object)0;}
以上方法仍然报“…内存损坏”
开始怀疑dll不是c++编译的,于是找反编译工具尝试
我找了两种,一种是depends22_x86,一种是pb反编译工具;通过depends22_x86可以看到dll的函数入口,并没有需要的函数,反编译工具编译出pb程序以后,就开始找新方向了;
pb的dll注册:需要pb运行环境,PB环境变量不需要配,把PB的支持库文件放到system32里就行了;也可以安装一下powerbuilder;或者把pb的*.dll和.exe放一起就可以跑PB程序了
参考:
C#调用PB写的com组件dll
C#WEBSERVICE调用PB生成的DLL
出结果以后还需注意
m_Com_Document.InvokeMember("f_sblwsk", BindingFlags.InvokeMethod, null, objDoc, new object[] {hospitalComb, RetStr });
这种方式,如果函数方法是出参ref或者out 类型时,参数值并未发生变化
解决方案:
object[] args = new object[2];string RetStr = "123";args[0] = hospitalComb;args[1] = RetStr;ParameterModifier pMod = new ParameterModifier(2);pMod[1] = true;ParameterModifier[] mods = {pMod };Type m_Com_Document = Type.GetTypeFromProgID("PB90.n_yhinterface");object objDoc = Activator.CreateInstance(m_Com_Document);object tempObj = m_Com_Document.InvokeMember("f_sblwsk", BindingFlags.InvokeMethod, null, objDoc, args,mods,null,null);Console.WriteLine("args[1]:" + Convert.ToString(args[1]));Console.WriteLine("RetStr:" + Convert.ToString(RetStr));Console.WriteLine("tempObj:" + Convert.ToString(tempObj));RetStr = Convert.ToString(args[1]);string[] datas = RetStr.Split('|');Console.WriteLine("datas[0]:" + datas[0]);
参考:
使用数组
使用ParameterModifier
以上,解决
后续需要加强的部分:
反射值类型和引用类型,值的变化wcf和wpf的理解以上的理解会造成,有时已经找到答案了,因为认知缺陷就把正确答案pass掉了,也做了很多无用功,看网上的资料时,遇到别人的解决方案,需要耐心验证,不要走马观花