在C++項目中調用C#的API

最近在工作中的一個項目,需要使用C#編寫的SDK, 而我們項目的代碼是C++,如何利用C++調用C#SDK便成了一個問題。經過一番谷歌百度,最終採用CLR實現了C++對C#的調用。具體過程如下圖所示
過程圖示
假設在C#項目中我們現在有一個API “PrintNameToScreen()”, 我們通過例子一步一步來看如何具體實現。
Step 1. 使用C# 生成dll., 項目名稱叫做“DemoHelperLib”;
a. 打開VS2015, 選擇Visual C# 的’ClassLibray’選項
在這裏插入圖片描述
b.項目生成後,配置項目屬性, 其中 “Platform target”選擇‘x64’, 而Outputpath 則是生成dll的文件夾,最終的大型項目一般要配置到主項目的exe路徑下,這個後面會說到。
在這裏插入圖片描述
c.修改代碼內容,VS默認生成的文件名和類名是class1, 爲了使用方便,把類名改成DemoHelper,
並添加以下內容


        void PrintNameToScreen(string sName)
        {
            Console.Write("Hello" + sName);
        }

在這裏插入圖片描述

編譯,在項目路徑下的bin文,可以發現’DemoHelperLib.dll’已經生成,step1 到這裏就大工告成啦。
Step2.建立C++ CLR 工程,生成library
a. 用VS2015新建一個visaul C++ CLR class library項目,如下圖所示,項目名叫“DemoHelpCLRLib”
在這裏插入圖片描述
b. 打開項目設置,設置‘Use MFC in shared DLL ’在這裏插入圖片描述
c. 在生成的“DemoHelpCLRLib.h” 頭文件中,引入剛纔生成的“DemoHelper.dll“的路徑,還記得在step1中說的dll生成路徑嗎? 你可以把該路徑直接配置成CLR項目的生成路徑,對應本例是“D:\MoFei\Demo\DemoHelpCLRLib\x64\Debug”, 或者手動從bin folder下拷過來,不過不建議這樣做,不然每次C#項目有更新,都要重新拷貝一遍,很麻煩的。直接設置好生成路徑即可。
在頭文件引入

#using "..\x64\Debug\DemoHelpLib.dll"

頭文件添加如下代碼, 設計一個類‘DemoHelperCLRModule’用來作爲管理類,通過gcroot託管對象以實現調用C# API的效果。

// DemoHelpCLRLib.h

#pragma once
#include <afx.h>
#using "..\x64\Debug\DemoHelpLib.dll"

using namespace System;
using namespace System;
using namespace System::Windows;
using namespace System::Runtime;
using namespace System::Runtime::InteropServices;

class DemoHelperCLRModule 
{
public:
	DemoHelperCLRModule(void);
	~DemoHelperCLRModule(void);
protected:
	gcroot<DemoHelpLib::DemoHelper^> m_CFXHelper;

public:
	bool PrintNameToScreen(CString sName );
};

在源文件中代碼如下:

#include "stdafx.h"
#include "DemoHelpCLRLib.h"

//重要,建立CLR託管對象
DemoHelperCLRModule::DemoHelperCLRModule(void)
{
	m_CFXHelper = gcnew DemoHelpLib::DemoHelper();
}
DemoHelperCLRModule::~DemoHelperCLRModule(void)
{
}
bool DemoHelperCLRModule::PrintNameToScreen(CString szName)
{
	bool bRet(true);
	if (m_CFXHelper) //個人習慣,可以不要
	{ 
	    //CLR 訪問要求,建立新對象時必須要用^, 具體可以查詢CLR語法。
		String^ sMyName = Marshal::PtrToStringAnsi((IntPtr)szName.GetBuffer());
        //調用C# API
	   m_CFXHelper->PrintNameToScreen(sMyName);
	}
	return bRet;
}

d. 做完上面的步驟,編譯過後,在項目路徑“x64\Debug”下面我們得到了"DemoHelpCLRLib.dll", 在主項目中添加該dll 和對應頭文件,便可以使用了,但通常在實際項目中,我們還會包一層導出管理類"DemoHelperModule"供主項目調用,這樣主項目就避免了直接訪問CLR託管項目,實現瞭解耦的目的。體系結構如下圖所示:
在這裏插入圖片描述
因此在CLR工程下再添加一對源文件和頭文件‘DemoHelpModule’,
在頭文件中添加

#pragma once
#include <afx.h>

class DemoHelperCLRModule; //CLR 類前置聲明
using namespace std;

class AFX_EXT_CLASS DemoHelpModule //導出類
{
public:
	DemoHelpModule(void);
	~DemoHelpModule(void);
private:
	DemoHelperCLRModule* m_pCLRModule; //CLR 託管類指針,爲了訪問CLR託管類
public:
	bool PrintYourNameToScreen(CString szName);
};

在源文件文件中添加:

#include "StdAfx.h"
#include "DemoHelpModule.h"
#include "DemoHelpCLRLib.h"

DemoHelpModule::DemoHelpModule(void)
{
	m_pCLRModule = new DemoHelperCLRModule();
}
DemoHelpModule::~DemoHelpModule(void)
{
	if (m_pCLRModule != NULL)
	{
		delete m_pCLRModule;
		m_pCLRModule = NULL;
	}
}

bool DemoHelpModule::PrintYourNameToScreen(CString szName)
{
	bool bRet = m_pCLRModule->PrintNameToScreen(szName);
	return bRet;
}

到這裏大功告成,我們已經生成想要的DemoHelpCLR.lib"與 “DemoHelpCLR.dll”,一般默認在x64文件夾下,把這兩個文件拷貝到C++主項目中,便可以愉快的調用C# API啦。
Step 3 建立主項目(調用C# 的c++項目)
我們以"Test Demo 爲例", 建立一個win32 console application 空項目,我就不放圖示過程了,這裏主要想說如何把剛在兩個我們建立的C# 項目和CLR項目添加進來,然後如何在C#裏進行debug。
a. 去到我們已有的CLR項目文件夾‘DemoHelpCLRLib’ 下, 複製項目(注意不是solution)所在文件夾,
在這裏插入圖片描述
把他拷貝到我們的TestDemo 的項目文件夾下, 同樣的操作拷貝C#項目文件下的‘DemoHelpLib’文件夾到 'TestDemo’文件夾下,拷貝完成後如圖所示
在這裏插入圖片描述
b. 在剛纔建立好的空項’TestDemo’中,右擊項目(solution)名稱,然後添加已有項目,分別把剛纔我們的拷貝的C#項目和CLR項目添加進來

在這裏插入圖片描述
添加好後,此項項目列表應該如下圖所示,在TestDemo solution下面有3個工程,分別是’DemoHelpCLRLib’,'DemoHelpLib’與‘TestDemo’
在這裏插入圖片描述
C. 配置C#項目dll輸出路徑,該路徑實際上就是我們’TestDemo’的exe生成文件目錄,一般就是在’x64/Debug’中
在這裏插入圖片描述
d.配置主項目的依賴頭文件路徑和依賴庫,即我們‘TestDemo’需要用到的lib以及頭文件。
首先頭文件配置,添加管理類‘DemoHelperModule’頭文件所在路徑,
在這裏插入圖片描述
e.其次添加依賴庫路徑以及 ‘DemoHelpCLRLib.lib’
在這裏插入圖片描述
在這裏插入圖片描述
到此大功告成,我們在主項目‘TestDemo’下建一個源文件 ‘TestDemo.cpp’,輸入以下測試代碼

#include <iostream>
#include "DemoHelpModule.h"


int main()
{
	DemoHelpModule* pTest = new DemoHelpModule;
	CString szName = "Tom";
	pTest->PrintYourNameToScreen(szName);
	system("Pause");
	return 0;
}

運行,屏幕上會打印出 ‘HelloTom’

常見編譯錯誤:
1.MFC share library error.
2. Can not resolve symbol
將C++主項目和CLR項目的use of MFC 設置成"Use MFC in a shared DLL" , 將 Character Set 設置統一格式,此例中設爲‘Not set’
在這裏插入圖片描述
3.C# dll output 路徑設置不正確。
4.主項目沒有添加頭文件依賴路徑
5.主項目沒有添加.lib文件依賴路徑與lib路徑。
6.把主項目設置成爲啓動項。
請逐一檢查上述設置是否正確,然後多編譯幾次,因爲有文件生成,一般第一遍編譯有error,再編譯一次就好了。

好了到此我們已經可以在C++項目調用C# API了, 那麼如何在C#中進行調試呢?只要在C#項目中設置主項目exe路徑即可。
在C# 項目設置選項中,在Debug選項那一欄設置主項目exe路徑,如下圖所示
在這裏插入圖片描述
然後選擇以C# debug 方式啓動項目,即可在C# API 重加斷點進行調試
在這裏插入圖片描述
到此,我們可以愉快的在我們C++項目中使用C# API啦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章