非托管C++通過C++/CLI包裝調用C# DLL


項目中要給其它客戶程序提供DLL做為接口,該項目是在.Net4.0平台下開發。終所周知.Net的各個版本之間存在着兼容性的問題,但是為了使用高版本運行平台的新特性,又不得不兼顧其它低版本平台客戶程序的調用。為了解決這個問題嘗試通過一個C++/CLI DLL對高版本的.Net DLL的接口加了一層包裝,對外暴露C風格的接口給客戶程序調用。

可支持的客戶語言平台:

  • VB 6.0
  • VC++
  • .Net 1.0/.Net 1.1
  • .Net 2.0
  • .Net 3.5

 

 創建C# .Net4.0的類庫

  • 創建一個C#項目:Csharp

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Csharp
{
    public class CsharpClass
    {
        public int DoTesting(int x, int y, string testing, out string error)
        {
            error = testing + " -> testing is ok.";
            return x + y;
        }
    }
}

 

創建C++/CLI包裝類庫

  • 創建項目C++/CLI項目:CsharpWrap

  • 添加對Csharp的引用

  • CsharpWrap.h

// CsharpWrap.h

#pragma once

#include <windows.h>  
#include <string> 

using namespace System;
using namespace Csharp;
using namespace std;
using namespace Runtime::InteropServices;
  • CsharpWrap.cpp

// This is the main DLL file.

#include "stdafx.h"

#include "CsharpWrap.h"

extern "C" _declspec(dllexport) int DoTesting(int x, int y, char* testing, char* error)
{
    try
    {
        CsharpClass ^generator = gcnew CsharpClass();
        String^ strTesting = gcnew String(testing);
        String^ strError;

        int sum = generator->DoTesting(x, y,strTesting, strError);

        if(strError != nullptr)
        {
            char* cError = 
                (char*)(Marshal::StringToHGlobalAnsi(strError)).ToPointer();
            memcpy(error,cError,strlen(cError) + 1);
        }
        else
        {
            error = nullptr;
        }

        return sum;
    }
    catch(exception e)
    {
        memcpy(error,e.what(),strlen(e.what()) + 1);
        return -1;
    }
}
  • 項目輸出和使用

  1. Csharp.dll
  2. CsharpWrap.dll

如果要調用CsharpWrap.dll必須保證Csharp.dll也被調用程序可見(即應該放在進程EXE文件同一目錄下)

 

調用Demo代碼

  • C++

HINSTANCE hInst= LoadLibrary(_T("CsharpWrap.dll"));
if(hInst)
{
    pfunc DoTesting = (pfunc)GetProcAddress(hInst,"DoTesting");

    if(DoTesting)
    {
        char error[100]= {NULL};
        int sum = DoTesting(1, 2, "Hello", error);
        //show testing results
        char strSum[8];
        _itoa_s(sum,strSum,16);
        ::MessageBoxA(NULL, error, strSum, MB_OK);
    }
    else
    {
        ::MessageBoxA(NULL, "Get function fail.", "Fail", MB_OK);
    }
    //free library
    FreeLibrary(hInst);
    hInst = nullptr;
}
else
{
    ::MessageBoxA(NULL, "Load dll fail.", "Fail", MB_OK);
}
  • C#低版本.Net

導出函數

[DllImport("CsharpWrap.dll")]
static extern int DoTesting(int x, int y, string testing, StringBuilder error);

調用

StringBuilder sb = new StringBuilder(200);
int sum  = DoTesting(1, 2, "Hellow", sb);
MessageBox.Show(sb.ToString(), sum.ToString());
  • VB6.0

導出函數

Public Declare Function DoTesting Lib "CsharpWrap.dll" (ByVal x As Integer, ByVal y As Integer, ByVal testing As String, ByVal error As String) As Integer

調用

Dim error As String
Dim testing As String
Dim x As Integer
Dim y As Integer
Dim sum As Integer

testing = "Hello"
error = String(60000, vbNullChar)
sum = DoTesting(x, y, testing, error)

 

常見問題及注意事項

  • 平台工具集的問題

如果使用的是VS2010以上的版本編譯出來的C++/CLI DLL可能會遇到缺少依賴等運行錯誤。

如果要支持XP系統工具集盡量用_xp結尾的

平台工具集的依賴DLL,把下面的或其它相應版本的依賴DLL放到目標機器的C:\WINDOWS\SYSTEM32下

      1. msvcp100.dll
      2. msvcr100.dll
      3. msvcp110.dll
      4. msvcr110.dll

 

  • 字符集的問題,因為.Net默認用的字符集是Unicode,但是客戶程序有可能是其它字符集,這樣也可能會造成字符串在程序間的兼容問題。

可選擇Unicode/Multi-Byte,根據不項目需求選擇相應的字符集

代碼內對不同字符集進行轉換

從char* to 寬字符

wchar_t *GetWC(const char *c)
{
    const size_t cSize = strlen(c)+1;
    wchar_t* wc = new wchar_t[cSize];
    MultiByteToWideChar(CP_ACP,0,(const char *)c,int(cSize),wc,int(cSize));    
    return wc;
}

String^ to Char*

char* cError = (char*)(Marshal::StringToHGlobalAnsi(strError)).ToPointer();

 

  • 調用的C++/CLI DLL的時候傳入參數的問題

C#調用的時候String參數對應的類型應該是StringBuilder,要注意StringBuilder的容量,默認是256個字符,如果返回的比較多的東西要注意初始化相應大小的容量。

 

  • DLL多層嵌套的問題

如果用LoadLibrary加載DLL失敗,可以嘗試用LoadLibraryEx,同時保證所依賴的C#DLL放到進程EXE同級目錄。

LoadLibraryEx("DLL絕對路徑", NULL, LOAD_WITH_ALTERED_SEARCH_PATH);

 

轉載請注明出處:http://www.cnblogs.com/keitsi/p/5554110.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM