1. 简介
随着Windows的发展,基于.Net的功能越来越多,使用也越来越方便。早期的.Net主要是C#和VB.NET进行开发。Windows希望几种主要的语言都能够统一,大家互相调用。Windows提供了CLR(Common Language Runtime),来统一各语言编译后的标准。另外还提供了.Net库,包括非常多的相关.Dll,提供功能API供调用。
2. 托管C++基本语法
托管,意味着内存的申请释放都统一交给CLR来处理。所以托管C++扩展了标准C++,提供了托管类。.NET中,所有类型都是对象类型。所以C++调用.NET中的API,都必须使用托管类型,以保持匹配。
2.1. 托管C++类型
2.1.1. 字符串
c#中的字符串
String str = “abc”;
托管C++中调用.NET字符串
String^ str = “abc”;
std::string strVal = “abc”;
托管字符串与标准字符串相互转换
String^ stdVal = marshal_as<String^>(strVal);
std::string strNew = marshal_asstd::string(stdVal);
2.1.2. 数组
c#中数组也是对象类型
String[] strArr = {“abc”, “bc”, “dd”};
托管C++调用.NET中数组类型
array<System::String > strArr = {“abc”, “abc”};
// gcnew,托管堆上申请内存,由托管自动管理释放
array<System::String > strArr1 = gcnew array<String^>(1) { “a” };
// 托管类型类似于指针,获批数组大小
int nCount = strArr->Length;
2.1.3. 基本类型
.NET中int等也有相应的对象类型
System.Int32 a;
System.Int16 b;
2.2. 调用
2.2.1. 引用
void Test(int % i) {
i++;
}
String^% stdValRef = stdVal;
2.2.2. 调用
.NET中大量使用命令空间。
C#调用
Console.WriteLine(“Hello world!”);
托管C++中
Console::WriteLine(“Hello world!”);
3. 示例
3.1. 调用.NET中的VisualStudio
VS2010中的coverage文件转成xml文件,需要用到.NET的功能。
C#代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Coverage.Analysis;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
if (args.Length < 3)
{
Console.WriteLine("Transform the coverage file to xml file.\r\n" +
"\r\n" +
"Coverage2xml coveragePath dllDir xmlPath\r\n" +
" coveragePath: xx.coverage file path.\r\n" +
" dllPath: the directory of unit test project's dll.\r\n" +
" xmlPath: the xml path for output.\r\n" +
"\r\n" +
"example: Coverage2xml e:\\data.coverage e:\\debug e:\\xx.xml");
return;
}
string coveragePath = args[0];
string dllDir = args[1];
string xmlPath = args[2];
using (CoverageInfo info = CoverageInfo.CreateFromFile(coveragePath, new string[] { dllDir }, new string[] { dllDir }))
{
CoverageDS data = info.BuildDataSet();
data.WriteXml(xmlPath);
}
}
}
}
托管C##代码:
#include <iostream>
using namespace System;
using namespace System::Collections;
using namespace Microsoft::VisualStudio::Coverage::Analysis;
int main(array<System::String ^> ^args)
{
if (args->Length < 3)
{
Console::WriteLine("Transform the coverage file to xml file.\r\n" +
"\r\n" +
"Coverage2xml coveragePath dllDir xmlPath\r\n" +
" coveragePath: xx.coverage file path.\r\n" +
" dllPath: the directory of unit test project's dll.\r\n" +
" xmlPath: the xml path for output.\r\n" +
"\r\n" +
"example: Coverage2xml e:\\data.coverage e:\\debug e:\\xx.xml");
return 0;
}
String^ a = gcnew String("abc");
String^ coveragePath = args[0];
String^ dllDir = args[1];
String^ xmlPath = args[2];
CoverageInfo^ info = CoverageInfo::CreateFromFile(coveragePath, gcnew array<String^>(1) { dllDir }, gcnew array<String^>(1){dllDir });
{
CoverageDS^ data = info->BuildDataSet();
data->WriteXml(xmlPath);
}
return 0;
}
3.2. 调用.NET中的Excel
C#代码:
using System;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;
namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Excel.Application xlApp ;
Excel.Workbook xlWorkBook ;
Excel.Worksheet xlWorkSheet ;
object misValue = System.Reflection.Missing.Value;
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Add(misValue);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
//add data
xlWorkSheet.Cells[1, 1] = "";
xlWorkSheet.Cells[1, 2] = "Student1";
xlWorkSheet.Cells[1, 3] = "Student2";
xlWorkSheet.Cells[1, 4] = "Student3";
xlWorkSheet.Cells[2, 1] = "Term1";
xlWorkSheet.Cells[2, 2] = "80";
xlWorkSheet.Cells[2, 3] = "65";
xlWorkSheet.Cells[2, 4] = "45";
xlWorkSheet.Cells[3, 1] = "Term2";
xlWorkSheet.Cells[3, 2] = "78";
xlWorkSheet.Cells[3, 3] = "72";
xlWorkSheet.Cells[3, 4] = "60";
xlWorkSheet.Cells[4, 1] = "Term3";
xlWorkSheet.Cells[4, 2] = "82";
xlWorkSheet.Cells[4, 3] = "80";
xlWorkSheet.Cells[4, 4] = "65";
xlWorkSheet.Cells[5, 1] = "Term4";
xlWorkSheet.Cells[5, 2] = "75";
xlWorkSheet.Cells[5, 3] = "82";
xlWorkSheet.Cells[5, 4] = "68";
Excel.Range chartRange ;
Excel.ChartObjects xlCharts = (Excel.ChartObjects)xlWorkSheet.ChartObjects(Type.Missing);
Excel.ChartObject myChart = (Excel.ChartObject)xlCharts.Add(10, 80, 300, 250);
Excel.Chart chartPage = myChart.Chart;
chartRange = xlWorkSheet.get_Range("A1", "d5");
chartPage.SetSourceData(chartRange, misValue);
chartPage.ChartType = Excel.XlChartType.xlColumnClustered;
xlWorkBook.SaveAs("csharp.net-informations.xls", Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
xlWorkBook.Close(true, misValue, misValue);
xlApp.Quit();
releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlApp);
MessageBox.Show("Excel file created , you can find the file c:\\csharp.net-informations.xls");
}
private void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Exception Occured while releasing object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
}
}
托管C++代码:
using namespace System;
using namespace System::Collections;
using namespace Microsoft::VisualStudio::Coverage::Analysis;
using namespace Microsoft::Office::Interop::Excel;
void TestExcel()
{
System::Object^ misValue = System::Reflection::Missing::Value;
Microsoft::Office::Interop::Excel::Application^ xlApp = gcnew Microsoft::Office::Interop::Excel::Application();
Microsoft::Office::Interop::Excel::Workbook^ xlWorkBook = xlApp->Workbooks->Add(misValue);
Microsoft::Office::Interop::Excel::Worksheet^ xlWorkSheet = (Microsoft::Office::Interop::Excel::Worksheet^)xlWorkBook->Worksheets[1];
xlWorkSheet->Cells[1, 1] = "";
xlWorkSheet->Cells[1, 2] = "Student1";
xlWorkSheet->Cells[1, 3] = "Student2";
xlWorkSheet->Cells[1, 4] = "Student3";
xlWorkSheet->Cells[2, 1] = "Term1";
xlWorkSheet->Cells[2, 2] = "80";
xlWorkSheet->Cells[2, 3] = "65";
xlWorkSheet->Cells[2, 4] = "45";
xlWorkSheet->Cells[3, 1] = "Term2";
xlWorkSheet->Cells[3, 2] = "78";
xlWorkSheet->Cells[3, 3] = "72";
xlWorkSheet->Cells[3, 4] = "60";
xlWorkSheet->Cells[4, 1] = "Term3";
xlWorkSheet->Cells[4, 2] = "82";
xlWorkSheet->Cells[4, 3] = "80";
xlWorkSheet->Cells[4, 4] = "65";
xlWorkSheet->Cells[5, 1] = "Term4";
xlWorkSheet->Cells[5, 2] = "75";
xlWorkSheet->Cells[5, 3] = "82";
xlWorkSheet->Cells[5, 4] = "68";
Microsoft::Office::Interop::Excel::ChartObjects^ xlCharts = (Microsoft::Office::Interop::Excel::ChartObjects^)xlWorkSheet->ChartObjects(Type::Missing);
Microsoft::Office::Interop::Excel::ChartObject^ myChart = (Microsoft::Office::Interop::Excel::ChartObject^)xlCharts->Add(10, 80, 300, 250);
Microsoft::Office::Interop::Excel::Chart^ chartPage = myChart->Chart;
Microsoft::Office::Interop::Excel::Range^ chartRange = xlWorkSheet->Range::get("A1", "d5");
chartPage->SetSourceData(chartRange, misValue);
chartPage->ChartType = Microsoft::Office::Interop::Excel::XlChartType::xlColumnClustered;
xlWorkBook->SaveAs("e:\\csharp.net-informations.xls", Microsoft::Office::Interop::Excel::XlFileFormat::xlWorkbookNormal, misValue, misValue, misValue, misValue, Microsoft::Office::Interop::Excel::XlSaveAsAccessMode::xlExclusive, misValue, misValue, misValue, misValue, misValue);
xlWorkBook->Close(true, misValue, misValue);
xlApp->Quit();
System::Runtime::InteropServices::Marshal::ReleaseComObject(xlWorkSheet);
System::Runtime::InteropServices::Marshal::ReleaseComObject(xlWorkBook);
System::Runtime::InteropServices::Marshal::ReleaseComObject(xlApp);
GC::Collect();
}
完整示例见附件。
4. 托管与非托管
托管C++有特殊的语法,编译的规则也有变化,默认生成的接口与标准C++不兼容。
如果在托管C++中想使用标准C++编译,可以使用
#pragma unmanaged和#pragma managed
4.1. 非托管封装托管代码
创建一个CLR的DLL工程,在其中添加如下代码,就可以导出标准C++的接口供标准C++工程使用了。完整示例见附件。
// .h
#pragma once
#pragma unmanaged
#ifdef TT_EXPORTS
#define TT_API __declspec(dllexport)
#else
#define TT_API __declspec(dllimport)
#endif
class TT_API Calc
{
public:
Calc(void);
int Add(int a, int b);
};
#pragma managed
// .cpp
#include "StdAfx.h"
#include "Calc.h"
#include <string>
#include <msclr\marshal.h>
#include <msclr\marshal_cppstd.h>
using namespace System;
using namespace System::Collections;;
using namespace msclr::interop;
void Test(std::string str)
{
String^ stdToCli = marshal_as<String^>(str);
Console::WriteLine(stdToCli);
}
#pragma unmanaged
Calc::Calc(void)
{
}
int Calc::Add(int a, int b)
{
Test("Hello World!");
return a+b;
}
#pragma managed