匯出 (0) 列印
全部展開

在 Azure 應用程式中執行 Unmanaged 程式碼的最佳作法

更新日期: 2014年6月

撰寫 Azure 應用程式適用的 .NET 程式碼時,大部分都類似於撰寫 Windows 應用程式適用的 .NET 程式碼。當您撰寫某個平台與另一個平台所適用的 .NET 程式碼時,必須留意一些細微的差異。本文將提供在 Azure 應用程式中執行 Unmanaged 程式碼/機器碼的建議。

作者:Christian Martinez、Trace Young 和 Mark Simms

下列章節將提供當您開發可呼叫機器碼的 Azure 應用程式時,可確保機器碼正確執行的建議。

若要設定機器碼在發行模式中編譯,請以滑鼠右鍵按一下機器碼專案,並選取 [屬性] 來顯示 [屬性] 頁面,然後從屬性頁面的 [建立] 索引標籤選取可用的 [發行] 組態選項:

note附註
執行階段錯誤指出您遺漏 DLL (例如 msvcr100d.dll 或 msvcp100d.dll),表示您部署的機器碼之前是在偵錯模式下編譯。msvcr100d.dll 和 msvcp100d.dll 檔案不是可轉散發 DLL。如需有關如何判斷要轉散發哪些 C++ DLL 檔案的詳細資訊,請參閱<判斷要轉散發哪些 DLL>(http://go.microsoft.com/fwlink/p/?LinkId=236016)。

遵循以下步驟來確定在 Azure 計算模擬器中執行時,Azure 應用程式可以找到任何參考的機器碼:

  1. 在 Visual Studio 中為編譯的機器碼檔案設定適當的屬性

    併入編譯的機器碼檔案當做專案項目,然後在 [屬性] 對話方塊上,針對檔案將 [複製到輸出目錄] 選項設定為 [永遠複製],並將 [建置動作] 選項設定為 [無]

    這樣會將編譯的機器碼檔案複製到 \bin 目錄,並確定您的 Azure 應用程式在 Azure 計算模擬器中執行時,可以找到編譯的機器碼檔案。



  2. 當您在 Azure 計算模擬器中排除 RoleEntry 實作的問題時,如果您將編譯的機器碼檔案複製到 devfabric 執行階段目錄,則偵錯問題會變得更輕鬆

    • 例如,當使用 Azure SDK 1.5 版或更早的版本時,請將編譯的機器碼檔案複製到以下目錄中:


      C:\Program Files\Azure SDK\[SDK Version]\bin\devfabric\x64\


    • Or, when using Azure SDK version 1.6 or later copy the compiled native code file to this directory:


      C:\Program Files\Azure SDK\[SDK Version]\bin\runtimes\base\x64\

  3. 確定在 Web 角色執行個體中執行的 Azure 應用程式可以找到任何參考的機器碼

    如果 Azure 應用程式參考的機器碼使用 C++/CLI 包裝,而且 Azure 應用程式在 Web 角色執行個體中執行,請使用下列其中一個方法來確定 Azure 應用程式可以找到參考的機器碼:



    note附註
    以下步驟會參考 PinvokeCppCliInAzure.zip 中範例程式碼所提供的 CppCliWebRole 專案,您可從 http://azureunmanagedcode.codeplex.com/ 下載這個檔案。如需有關此範例程式碼的詳細資訊,此參閱範例程式碼:從 Azure 應用程式執行機器碼

    方法 1:編輯 PATH 環境變數,然後重新啟動 Azure 計算模擬器和 IIS:

    1. 停止及結束 Azure 計算模擬器。

    2. 編輯您的 PATH 環境變數,以指向包含編譯之機器碼的目錄。

    3. 從更高權限的命令提示字元輸入 iisreset

    4. F5 執行範例程式碼。

    方法 2:使用啟動命令

    在底下的步驟中,機器碼位於 ExampleNativeCode.dll 檔案中。

    1. 停止及結束 Azure 計算模擬器。

    2. 開啟 CppCliWebRole 專案隨附的 indist.cmd 檔案。

    3. 將以下這一行:

      REM copy "%~dps0ExampleNativeCode.dll" "%windir%\system32\inetsrv"
      
      收件者:



      copy "%~dps0ExampleNativeCode.dll" "%windir%\system32\inetsrv"
      
    4. 儲存專案。

    5. F5 執行範例程式碼。

    note附註
    啟動命令的使用對於實際部署同樣有效。如果您想要避免參考 IIS 系統目錄,您可以選擇建立及執行指令碼進行以下作業:

    1. 變更 PATH 環境變數,以指向包含編譯之機器碼的目錄。

    2. 重新啟動 IIS 以及與它相依的所有處理序。

Azure 是 64 位元平台,正如 Azure 主應用程式 (工作者和 Web 角色) 一樣。如果您未使用單純的 64 位元開發環境,而且您的應用程式參考機器碼,您的應用程式將會擲回錯誤。有一個簡單測試可以確認您參考的所有機器碼都是 64 位元,就是使用硬式編碼的主控台測試應用程式當做 64 位元應用程式執行來測試機器碼。

根據預設,只有 Visual C++ 2008 適用的 Visual C++ 執行階段程式庫會安裝在 Azure 工作者角色和 Web 角色上。因此,針對 Visual C++ 其他版本適用的 Visual C++ 執行階段程式庫編譯的機器碼將無法在背景工作角色和 Web 角色執行個體中載入。如果在同一部電腦上同時安裝了 Visual Studio 2008 與較新版本,您可以搭配 Visual Studio 2008 平台工具組 (編譯器、連結器、標頭和程式庫) 使用 Visual Studio 的原生多目標功能,為您的應用程式建置原生程式庫。如需有關搭配 Visual Studio 2008 平台工具組使用 Visual Studio 建置應用程式的詳細資訊,請參閱<作法:修改目標 Framework 和平台工具組(http://go.microsoft.com/fwlink/?LinkId=324964)。

您可以將更高權限的啟動工作加入至背景工作角色或 Web 角色專案,以複製及安裝必要的執行階段程式庫版本。下列步驟描述如何建立更高權限的啟動工作,將 64 位元版本的 Microsoft Visual C++ 2010 可轉散發套件複製到背景工作/Web 角色,並執行這個可轉散發套件,以便將 Visual C++ 2010 適用的 Visual C++ 程式庫安裝到背景工作/Web 角色執行個體。其他 Visual C++ 版本需要該版本特有的可轉散發套件:

  1. 為您的工作者或 Web 角色專案建立啟動資料夾。

  2. vcredist_x64.exe (http://go.microsoft.com/fwlink/p/?LinkId=225987) 複製到啟動資料夾。

  3. 在啟動資料夾中建立 startup.cmd 檔案。

  4. Edit startup.cmd and add the following line:


    "%~dps0vcredist_x64.exe" /q /norestart


  5. 從 Visual Studio 的 [方案總管] 修改 vcredit_x64.exestartup.cmd 的屬性。將 [建置動作] 選項設定為 [內容],並將 [複製到輸出目錄] 選項設定為 [有更新時才複製]

  6. 加入以下更高權限的啟動工作來執行 startup.cmd,為此角色編輯 ServiceDefinition.csdef 檔案:


    < Task commandLine ="Startup\Startup.cmd" executionContext ="elevated" taskType ="simple" />

當 Azure 計算模擬器無法載入組件時所產生的錯誤訊息可能不是直覺式。若要針對在工作者或 Web 角色主機執行個體中載入檔案的問題進行疑難排解,請使用處理序監視器,如下所示:

  1. 請從處理序監視器 v2.96 (http://go.microsoft.com/fwlink/p/?LinkID=137175) 下載處理序監視器。

  2. 啟動處理序監視器,針對 Azure 應用程式在 Azure 計算模擬器中執行時所發生的載入檔案問題進行疑難排解。

  3. 針對 Azure 計算模擬器主機設定篩選參數,如底下所述。如果針對工作者角色專案中執行的 Azure 應用程式進行疑難排解,請變更篩選來顯示處理序名稱為 WaWorkerHost.exe (而不是 WaWebHost.exe) 的項目:







  4. 尋找任何 NAME_NOT_FOUND 訊息。這樣有助於隔離遺漏的程式庫檔案。一旦您判定哪一個檔案遺失,您就可以套用篩選來隔離只與該檔案相關的訊息,以縮小搜尋範圍。

若要讓 Azure 應用程式使用 P/Invoke 執行 64 位元機器碼,請先使用 .NET 完全信任層級設定關聯的工作者或 Web 角色。如需有關從 Azure 工作者角色或 Web 角色中執行的應用程式呼叫機器碼的詳細資訊,請參閱下列資源:

本章節描述 PinvokeCppCliInAzure.zip (http://go.microsoft.com/fwlink/p/?LinkId=236170) 中的範例程式碼,您可從 http://azureunmanagedcode.codeplex.com/ 下載這個檔案。

note附註
當您從 Visual Studio 使用 Azure 計算模擬器來逐步執行範例程式碼時,不必執行啟動命令中安裝 Visual C++ 執行階段程式庫的部分,因此您應該將 startup.cmd 檔案中的下面這一行標記為註解:

REM "%~dps0vcredist_x64.exe" /q /norestart

此範例程式碼包含一個專案,該專案會建立稱為 ExampleNativeCode.dll 的原生 DLL。此 DLL 已經依照建議,在發行模式中編譯為 64 位元程式庫。

note附註
每當您在程式碼或 Windows 環境變數有任何變更時執行任何範例程式碼時,請結束 Azure 計算模擬器,然後將它重新啟動。如此將可確保任何參考的機器碼都可從記憶體中釋出,好讓機器碼可以重新編譯,而且下次執行時,Azure 計算模擬器也會網羅任何環境變數變更。

範例程式碼 ExampleNativeCode.dll 會在稱為 ManagedUsingPinvoke 的專案中使用 P/Invoke 包裝,而且在稱為 ManagedUsingCppCLI 的專案中使用 C++/CLI 包裝。

原生 DLL 中的程式碼是修改版的預設 Win32 專案範本 (包含匯出),而且包含單一函數來回答宇宙中所有已知的問題,前提是這些問題的解答為數字 42:

EXAMPLENATIVECODE_API int fnExampleNativeCode(void)
{
    return 42;
}

利用這個函數的 P/Invoke 程式碼和 C++/CLI 程式碼十分類似:

P/Invoke

public class Class1
{
    [DllImport("ExampleNativeCode.dll")]
    static extern int fnExampleNativeCode();

    public int GetTheAnswerToEverything()
    {
        return fnExampleNativeCode();
    }
}

C++/CLI

public ref class Class1
{
public:

    int GetTheAnswerToEverything()
    {
        return fnExampleNativeCode();
    }
};

方案中的兩個工作者角色範例 (PInvokeWorkerRoleCppCliWorkerRole) 會以相同方式叫用程式碼:

try
{
    Trace.WriteLine(new Class1().GetTheAnswerToEverything());
}
catch (Exception ex)
{
    Trace.WriteLine(ex);
}

這兩個工作者角色範例都包含編譯的機器碼,而且都設定為永遠都會將編譯的機器碼複製到輸出目錄。

當您按下 F5 鍵在 Azure 計算模擬器中執行程式碼時,應該會看見下列輸出:

當從 Web 角色執行個體中執行的 Azure 應用程式呼叫機器碼時 (相較於在工作者角色執行個體中執行),必須考量某些事項。PInvokeWebRoleCppCliWebRole 專案會在稍微修改過的預設 ASP.NET 專案範本版本中包含以下程式碼:

P/Invoke

<p>
    This is PInvoke <br />
        <%=Environment.GetEnvironmentVariable("PATH") %> <br />
        <%=new Class1().GetTheAnswerToEverything() %>
</p>

C++/CLI

<p>
    This is C++/CLI <br />
        <%=Environment.GetEnvironmentVariable("PATH") %> <br />
        <%=new Class1().GetTheAnswerToEverything() %>
</p>

執行 PInvokeWebRole 專案將會產生類似於下面的預期輸出:

不過,在未修改 CppCliWebRole 專案的情況下執行它將會產生下列錯誤:

note附註
即使套用適當的專案設定,將編譯的機器碼複製到輸出目錄,依然會發生這個錯誤。

若要解決這個錯誤,請使用Ensure that Azure Applications Running in a Web Role Instance can Locate any Referenced Native Code中所描述的其中一個方法。在使用其中一個方法之後,您應該會看到 CppCliWebRole 頁面的預期輸出,如下所示:

顯示:
© 2014 Microsoft