2014-01-05 49 views
2

有沒有簡單的方法來創建一個Visual Studio解決方案,其中包含兩個項目 - 第一個創建.dll的ml64程序集和第二個調用.dll中的方法的C#程序?C#如何在沒有中間C++層的情況下直接調用ml64 dll?

例如:

ml64代碼文件div.asm:

 .code 
; ulong Divide (ref ulong rem, ulong dividend_low, ulong divisor) 
; sets rem to (rem*2^64 + dividend_low) mod divisor 
; return floor((rem*2^64 + dividend_low)/divisor) 
; assume &rem in rcx, dividend_low in rdx, divisor in r8 
Divide proc 
    mov rax,rdx 
    mov rdx,qword ptr [rcx] 
    cmp  rdx,r8 
    jae  ovfl 
    div r8 
    mov qword ptr [rcx],rdx 
ovfl: 
    ret 
Divide endp 
    end 

C#代碼文件main.cs:

using System; 
using System.Runtime.InteropServices;  // DLL support 

class HelloWorld 
{ 
    [DllImport("div.dll")] 
    public static extern ulong Divide (ref ulong rem, ulong dividend_low, 
             ulong divisor); 

    static void Main() 
    { 
     Console.WriteLine ("This is C# program"); 
     long quot, rem = 3, dividend_low = 1, divisor = 20; 
     Console.WriteLine("divide (3 * 2^64 + 1) by 20"); 
     quot = Divide(ref rem, dividend_low, divisor); 
     Console.WriteLine("quotient = {0}, remainder = {1}", quot, rem); 
    } 
} 

我想要這樣做不訴諸於中間如果可能的話,在C++層。 需要在VS中設置什麼設置? C#代碼是否需要使用PInvoke?如果是這樣如何?

+0

您的代碼是否工作?如果不是,它是做什麼的?你確定你的程序集遵循[StdCall調用約定](http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention)嗎? (我不知道有足夠的程序集來驗證。) – svick

回答

0

創建一個空的Visual C++ DLL項目並插入您的.asm文件,並進行編譯。然後使用DllImport從您的C#項目調用導出的方法。

2

你的方法是正確的,你只需要用你喜歡的任何非託管語言(在你的例子中是彙編語言)創建一個DLL,然後從C#端使用P/Invoke來調用它,沒有包裝需要做這樣的事情因爲C#可以直接調用非託管代碼。

需要注意的兩件事。在DLL方面,確保你導出你的函數入口點,以便外部調用者可以使用它(不確定這裏MASM如何處理這個,可能你必須放一些入口指示,但不確定)。 C#方面的另一件事是該項目必須被強制編譯爲x64(AnyCPU或x86在此處無效),因爲您明確地調用了非託管x64代碼。

除此之外,[DllImport]是要走的路。

+0

我確實需要在命令行中明確地放置/ EXPORT Divide,以便LINK命令給我我認爲是合適的DLL。 (至少dumpbin能夠識別dll並將Divide作爲入口點。)C#代碼絕對是一個x64平臺程序。但是,當我嘗試添加Div.dll作爲參考時,我收到消息「無法添加對'C:\ CSharp \ Troy5 \ x64 \ Debug \ Div.dll'的引用。請確保該文件是可訪問的,並且它是一個有效的程序集或COM組件。「我需要某種清單(無論是什麼)?感謝您的幫助。 – user113670

+0

也許有點晚,但沒有必要這些引用僅用於調用其他託管程序集或導入COM組件,但對於普通的C風格導出非託管庫,'[DllImport]'包含所有需要的信息對於調用,DLL實際上是在運行時加載的,所以不需要硬引用它。 – Alejandro

0

它的工作原理!下面是對於那些有興趣的細節:

大會ml64:

 .code 
; ulong Divide (ref ulong rem, ulong dividend_low, ulong divisor) 
; on entry rem is dividend_high 
; sets rem to (dividend_high*2^64 + dividend_low) mod divisor 
; return floor((dividend_high*2^64 + dividend_low)/divisor) 
; assume &rem in rcx, dividend_low in rdx, divisor in r8 
Divide proc 
    mov rax,rdx 
    mov rdx,qword ptr [rcx] 
    cmp rdx,r8 
    jae ovfl  ; overflow if divisor <= dividend_high (includes divide by 0) 
    div r8  ; dividend_high >= 0 && divisor > dividend_high => divisor > 0 
    mov qword ptr [rcx],rdx 
ovfl: 
    ret   ; ((ß-2)*ß + (ß-1))/(ß-1) = ((ß-1)*ß - 1)/(ß-1) = ß - 1/(ß-1) < ß 
Divide endp 
    end 

託管C#:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices;  // DLL support 

namespace Troy5 
{ 
    class Program 
    { 
     [DllImport(@"C:\CSharp\Troy5\x64\Debug\Div.dll")] 
     public static extern ulong Divide (ref ulong rem, ulong dividend_low, 
             ulong divisor); 

     static void Main (string[] args) 
     { 
      Console.WriteLine("This is C# program"); 
      ulong quot, rem = 3, dividend_low = 1, divisor = 20; 
      Console.WriteLine("divide (3 * 2^64 + 1) by 20"); 
      quot = Divide(ref rem, dividend_low, divisor); 
      Console.WriteLine("quotient = {0}, remainder = {1}", quot, rem); 
     } 
    } 
} 

訣竅是明確將 '/ EXPORT鴻溝' 在彙編程序的鏈接命令並且不要試圖將該dll包含在C#程序的參考文獻中。相反,我只是將dll的完整路徑放在程序中。其餘設置可以從以下命令行中推斷出來:

ml64.exe /c /nologo /Sa /Sg /Zi /Fo"C:\CSharp\Troy5\x64\Debug\div.obj" 
    /Fl"C:\CSharp\Troy5\Div\div.lst" /W3 /errorReport:none /Ta 

LINK /OUT:"C:\CSharp\Troy5\x64\Debug\Div.dll" /NOLOGO /DLL /DEBUG 
    /PDB:"c:\CSharp\Troy5\Div\x64\Debug\Div.pdb" /MAP":c:\CSharp\Troy5\Div\div.map" 
    /MAPINFO:EXPORTS /ASSEMBLYDEBUG /NOENTRY /MACHINE:X64 

確保正確設置構建依賴關係。

感謝Svick和Alejandro的幫助!

相關問題