C#调C++库返回字符串

用C#调C++库函数返回字符串,由于C++本身方法之间调用返回字符串都是一般都是申明void或int返回的方法,然后通过char变量带出返回值。在C++调用这种之前自己先初始化char空间,然后调用的方法把返回值放入char*。

类似下面的,通过oneLineMerge返回处理后的串。调用地方自己先申请足够的空间,然后传递char*

/// 
/// 把多个连续字符合并为一个
/// 
/// 源串
/// 要合并的字符
/// 输出串
void MergeCharToOne(char* source, char oneChar, char* retStr);


char oneLine[1024] = { 0 };
char oneLineMerge[1024] = { 0 };
//合并多个连续空格
MergeCharToOne(oneLine, ' ', oneLineMerge);


对应char*带返回值的如果直接用C#的string类型对接会报内存访问错误,或者内存溢出直接程序退出。对于传入参数,C++方法内部不修改的用C#的string对应没问题。

比如我这里有一个医保二维码转身份证的接口对方方法申明如下:

void NationEcTrans(char* url, char* input, char* output);

如果我用C#的P-Invok按下面对都不行。

//这种无法得到output
[DllImport("NationECCode.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void NationEcTrans(string url, string input, string output);

//这种程序直接退出
[DllImport("NationECCode.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void NationEcTrans(string url, string input,out string output);

//这种程序直接退出
[DllImport("NationECCode.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void NationEcTrans(string url, string input,ref string output);

按网上资料都是让char*对string的。其实这是有误解的,传入参数可以正常,带出字符串不行。这里就涉及到托管内存和非托管内存。string是C#的托管内存,传递给C++他是无法写入的,如果C++方法尝试修改内存就会异常了。所以对返回串要申请非托管内存。然后传入内存地址过去。

C++返回串参数C#用IntPtr对应

[DllImport("NationECCode.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void NationEcTrans(string url, string input, IntPtr output);

调用代码如下,先申请非托管内存然后把内存首地址传入,调用返回从申请内存提取数据,然后释放申请内存。

/// 
        /// 得到身份证
        /// 
        /// 
        public static string GetIdNo()
        {
            string input = "{\"data\":{\"orgId\":\"XXXXX\",\"businessType\":\"01101\",\"operatorId\":\"909\",\"operatorName\":\"insu\",\"officeId\":\"A09\",\"officeName\":\"其他\",\"deviceType\":\"\"},\"transType\":\"ec.query\",\"orgId\":\"H14110201536\"}";
            //申请足够接返回串的空间
            IntPtr outPut = System.Runtime.InteropServices.Marshal.AllocHGlobal(2048);
            NationEcTrans("http://10.30.20.249:80/localcfc/api/hsecfc/localQrCodeQuery", input, outPut);
            //{"code":0,"data":{"authNo":null,"birthday":null,"chnlId":null,"ecIndexNo":"AAAAAA","ecQrCode":null,"ecToken":"140000ecpuhch57k710100007f0000eff4b702","email":null,"gender":null,"idNo":"CCCCCCCCCC","idType":"01","insuOrg":"140100","nationality":null,"userName":"Tom"},"message":"成功","orgId":"H14110201536"}
            //从申请空间转换得到串
            string retStr = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(outPut);
            //释放空间
            System.Runtime.InteropServices.Marshal.FreeHGlobal(outPut);
            string startStr = "\"idNo\":\"";
            string idNo = "";
            if (retStr.Contains(startStr))
            {
                int startIndex = retStr.IndexOf(startStr);
                int endIndex = retStr.IndexOf("\"", startIndex + startStr.Length);
                idNo = retStr.Substring(startIndex+ startStr.Length+1, endIndex - startIndex- startStr.Length);
            }
            else
            {
                idNo = "-1^" + retStr;
                
            }
            return idNo;
        }

其实和C++自己调用方法通过char带出返回值一样。给出一个非托管内存首地址给调用方。这就是C#调用C++返回字符串对应类型的一个经验。理解C/C++自己调用就好理解了。而C++自己返回字符串为啥一般申明返回值不直接为string或char的原因主要是方法内部变量是局部变量,方法返回后就回收了。字符串是复杂类型,所以不适合返回char*。C#应该是托管环境处理了返回引用类型,一般都是各种引用类型直接返回了。

你可能感兴趣的:(C#,C++,c#,c++,java)