2012年4月24日 星期二

在C#中如何使用C/C++所編譯出來的dll?

最近因為有同學問到如何在C#中使用C/C++所事先產生出來的dll問題,在這邊也大概總結一下自己在嘗試這個問題所找到的資料,避免之後某一天需要用到又要重新google (關鍵字: marshal, DllImport)

結合多語言(如 Visual C++ 與 Visual C#)以便利軟體開發是.NET framework的重點核心之一。
廢話不多說,先來看如何在Visual C++中使用自己所產生出來的Dll[1]。
有了這個基本概念後,就可以知道要在Visual C++中創造一個dll,在該function/method的header file中要加上__declspec(dllexport),已確保該function/method可以被export到Dll中。
而對應的.cpp檔就只是單純的實做對應method的內容。

如[2]所說,微軟只提供C-function的marshal對應的方法(也就是以function-based的marshal,並沒有class level的marshal)。
所以如果要marshal一個C-functions的Dll還蠻容易的,可以參考[3] (注意,如果使用visual studio系列,把.so換成.dll就可以了)。

如果更複雜一些,需要marshal C++ class的Dll話(unmanaged Dll),可以參考[2]。
主要的做法就是利用C-functions的做法為該Class做封裝(Wrap),例如說可以提供function-based的方式存取以開發/設計好的class。(不過要Wrap的話有點複雜就是了 :( )

此外,如果要用C-function的marshal,需要額外注意C與C++之間的call convention的差異[4]。


底下列出小弟測試好的程式碼:

1. 定義已編好的C-functions DLL


---------- c_MathFuncsDll.h----------


#ifndef c_MathFuncsDll_H
#define c_MathFuncsDll_H

#include stdio.h;
extern "C"{

    // Returns a + b
  __declspec(dllexport) double Add(double a, double b);

  // Returns a - b
  __declspec(dllexport) double Subtract(double a, double b);

  // Returns a * b
  __declspec(dllexport) double Multiply(double a, double b);

  // Returns a / b
  __declspec(dllexport) double Divide(double a, double b);
    }
#endif

---------- c_MathFuncsDll.cpp----------

#include "c_MathFuncsDll.h"



double Add(double a, double b)
{
    return a + b;
}

double Subtract(double a, double b)
{
    return a - b;
}

double Multiply(double a, double b)
{
    return a * b;
}

double Divide(double a, double b)
{
    if (b == 0)
    {
        return -1;
    }

    return a / b;
}


1. 定義要呼叫C-functions Dll的C#檔(xxx/c_MathFuncsDll.dll為欲使用的library檔案)


using System;
using System.Runtime.InteropServices;

namespace Csharp_MyMathFuncs
{
    class Program
    {
        [DllImport("xxx/c_MathFuncsDll.dll", EntryPoint = "Add")]
        static extern double Add(double a, double b);
        [DllImport("xxx/c_MathFuncsDll.dll", EntryPoint = "Subtract")]
        static extern double Subtract(double a, double b);
        [DllImport("xxx/c_MathFuncsDll.dll", EntryPoint = "Multiply")]
        static extern double Multiply(double a, double b);
        [DllImport("xxx/c_MathFuncsDll.dll", EntryPoint = "Divide")]
        static extern double Divide(double a, double b);

        static void Main(string[] args)
        {
            double d1 = 5.0d;
            double d2 = 20.0d;
            Console.Write(Add(d1,d2));
        }
    }
}



參考連結:
[1] Walkthrough: Creating and Using a Dynamic Link Library
[2] How to Marshal a C++ Class
[3] PInvoke ( How to Call C from C# )
[4] LIst of Calling Conventions and Mangling Names in C++

1 則留言:

匿名 提到...

無法讀入DLL