C#调用PB生成dll详解

前言:调用dll时,需要先问清楚dll是由什么语言编译的,要不然方向错了会有很多无用功

试错过程:

  1. 直接引用出错:“…不是规范的COM组件”
  2. 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

使用以上方法遇到的报错

  1. 直接引用时,报错“尝试写入或读取受保护的内存,这通常是指内存已损坏”
  2. DllImport时,报错无法找到方法入口
  3. 无法加载该模块

解决方案思路:

  1. 最开始由于不知道dll是pb生成的,误当作c++生成的,所以当报错无法找到入口时,就怀疑提供方给错dll了,当时接口文档也没有说清楚,就一直在找这个问题。
  2. 后来注册了该dll,把相关的依赖项放进与exe同级目录下,就可以直接引用进去了
  3. 之后直接调用的时候,需要new一个对象,用过两种方式
  • 常见new
COClass_n_yhinterface b = new COClass_n_yhinterface();
  • 反射

```csharp
private 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);
            }//catch
            return (object)0;
        }

以上方法仍然报“…内存损坏”

  1. 开始怀疑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

  2. 出结果以后还需注意

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掉了,也做了很多无用功,看网上的资料时,遇到别人的解决方案,需要耐心验证,不要走马观花

你可能感兴趣的:(c#,工作日志)