共用方式為


如何:移轉至 /clr

本文討論使用 /clr編譯原生程序代碼時所發生的問題。 如需詳細資訊,請參閱 /clr (Common Language Runtime 編譯)/clr 允許原生C++程序代碼除了其他原生C++程序代碼之外,還可從 .NET 元件叫用和叫用。 如需使用 /clr編譯的優點詳細資訊,請參閱 混合式(原生和 Managed)元件原生和 .NET 互操作性

使用編譯連結庫專案的已知問題 /clr

使用 編譯連結庫專案 /clr時,Visual Studio 包含一些已知問題:

  • 您的程式代碼可能會在運行時間使用 CRuntimeClass::FromName查詢類型。 不過,如果類型位於 MSIL DLL 中(使用 /clr編譯),在 Managed DLL 中執行靜態建構函式之前,對的呼叫 FromName 可能會失敗。 (如果 FromName 呼叫是在 Managed DLL 中執行程式代碼之後發生,您就不會看到這個問題。若要解決此問題,您可以強制建構 Managed 靜態建構函式:在 Managed DLL 中定義函式、導出函式,並從原生 MFC 應用程式叫用函式。 例如:

    // MFC extension DLL Header file:
    __declspec( dllexport ) void EnsureManagedInitialization () {
       // managed code that won't be optimized away
       System::GC::KeepAlive(System::Int32::MaxValue);
    }
    

使用 Visual C++ 編譯

在專案中的任何模組上使用 /clr 之前,請先編譯原生專案,並將原生專案與Visual Studio連結。

依照順序遵循下列步驟,提供編譯的最簡單路徑 /clr 。 請務必在這些步驟之後編譯並執行您的專案。

從舊版 Visual Studio 升級

如果您要從舊版升級 Visual Studio,您可能會看到與 Visual Studio 中增強的標準C++一致性相關的編譯程序錯誤。

使用舊版Visual Studio建置的專案也應該先在沒有 的情況下 /clr編譯。 Visual Studio 現在已提高標準C++一致性和一些重大變更。 可能需要最注意的變更是 CRT中的安全性功能。 使用CRT的程式代碼可能會產生取代警告。 您可以隱藏這些警告,但建議移轉至新的 CRT 增強型版本的 CRT 函 式,因為它們可提供更佳的安全性,而且可能會顯示程式代碼中的安全性問題。

從受控擴充功能升級C++

在 Visual Studio 2005 和更新版本中,使用 Managed Extensions for C++ 撰寫的程式代碼將不會在 下 /clr編譯。

將 C 程式代碼轉換為C++

雖然 Visual Studio 會編譯 C 檔案,但必須將它們轉換成編譯C++ /clr 。 實際檔名不需要變更;您可以使用 /Tp (請參閱/Tc 、、/Tp/TC/TP (指定來源檔案類型)。 雖然需要C++原始程式碼檔案 /clr,但不需要重構程式代碼以使用面向物件的範例。

C 程式代碼在編譯為C++檔案時可能需要變更。 C++類型安全規則很嚴格,因此必須使用轉換明確類型轉換。 例如,malloc 會傳回 void 指標,但可以使用轉換指派給 C 中任何類型的指標:

int* a = malloc(sizeof(int));   // C code
int* b = (int*)malloc(sizeof(int));   // C++ equivalent

函式指標在 C++中也是絕對安全的類型,因此下列 C 程式代碼需要修改。 在C++中,最好建立 typedef 定義函式指標類型的 ,然後使用該類型來轉換函式指標:

NewFunc1 = GetProcAddress( hLib, "Func1" );   // C code
typedef int(*MYPROC)(int);   // C++ equivalent
NewFunc2 = (MYPROC)GetProcAddress( hLib, "Func2" );

C++也需要先建立原型或完整定義函式,才能參考或叫用函式。

在 C 程式代碼中使用的識別碼,必須重新命名C++中的關鍵詞(例如virtualnewdeletebooltruefalse等)。 這項變更通常可以使用簡單的搜尋和取代作業來完成。

COMObj1->lpVtbl->Method(COMObj, args);  // C code
COMObj2->Method(args);  // C++ equivalent

重新設定項目設定

在 Visual Studio 中編譯和執行項目之後,您應該為 /clr 建立新的項目組態,而不是修改預設組態。 /clr 與某些編譯程式選項不相容。 建立個別的組態可讓您將專案建置為原生或受控。 在 [屬性頁] 對話框中選取時 /clr ,會停用與 不相容 /clr 的項目設定。 (如果 /clr 稍後未選取,則不會自動還原停用的選項。

建立新的項目組態

您可以使用 [新增項目組態] 對話框[複製設定的來源] 選項,根據現有的專案設定建立項目組態。 針對 [偵錯] 組態建立組態的複本,一次用於發行組態。 接著,後續的變更只能套用至 /clr特定組態,讓原始項目組態保持不變。

使用自定義建置規則的專案可能需要額外的注意。

此步驟對於使用makefiles的專案有不同的影響。 在此情況下,可以設定個別的組建目標,或從原始複本建立編譯的特定 /clr 版本。

變更項目設定

/clr您可以遵循 /clr(Common Language Runtime 編譯)中的指示,在開發環境中選取。 如先前所述,此步驟會自動停用衝突的項目設定。

注意

從 Visual Studio 2003 升級 Managed 連結庫或 Web 服務專案時,編譯 /Zl 程式選項會新增至 命令行 屬性頁。 這會導致LNK2001錯誤。 從 /Zl] 屬性頁移除,以解決錯誤。 如需詳細資訊,請參閱 /Zl (省略默認連結庫名稱)設定編譯程式和建置屬性

針對使用makefiles建置的專案,新增之後 /clr ,必須手動停用不相容的編譯程序選項。 如需與 不相容 /clr之編譯程式選項的資訊,請參閱 /clr 限制

先行編譯標頭

在下 /clr支援先行編譯標頭。 不過,如果您只使用 /clr 編譯部分 CPP 檔案(將其餘檔案編譯為原生),則需要某些變更。 產生的 /clr 先行編譯標頭與在沒有 /clr的情況下產生的先行編譯標頭不相容,因為 /clr 會產生 和 需要元數據。 使用 編譯的 /clr 模組無法使用不包含元數據的先行編譯標頭,而且非/clr 模塊無法使用包含元數據的先行編譯頭檔。

使用 編譯某些模組 /clr 的專案,最簡單的方式是完全停用先行編譯的標頭。 (在 [項目屬性頁] 對話框中,開啟C/C++ 節點,然後選取 [先行編譯標頭]。然後將 Create/Use Precompiled Headers 屬性變更為「不使用先行編譯標頭」。

不過,特別是針對大型專案,先行編譯標頭可提供更佳的編譯速度,因此不建議停用此功能。 在此情況下,最好設定 /clr 和非/clr 檔案,以使用不同的先行編譯標頭。 您可以在一個步驟中設定它們:使用 方案總管 來多重選取要編譯的/clr模組。 以滑鼠右鍵按兩下群組,然後選取 [ 屬性]。 然後,將建立/使用 PCH 透過檔案先行編譯頭文件屬性變更為分別使用不同的頭檔名稱和 PCH 檔案。

修正錯誤

使用編譯程式代碼 /clr 可能會導致編譯程式、連結器或運行時間錯誤。 本節討論最常見的問題。

元數據合併

不同的數據類型版本可能會導致連結器失敗,因為為兩種類型產生的元數據不相符。 (當您有條件地定義類型的成員,但所有使用類型之 CPP 檔案的條件都不同時,就會發生錯誤。在此情況下,連結器會失敗,只報告符號名稱和定義類型的第二個 OBJ 檔案的名稱。 您可能會發現輪替 OBJ 檔案傳送至連結器的順序會很有用,以探索其他數據類型版本的位置。

載入器鎖定死結

可能會發生「載入器鎖定死結」,但具決定性,而且會在運行時間偵測並報告。 如需詳細的背景、指引和解決方案,請參閱 混合元件的 初始化。

數據匯出

匯出 DLL 數據很容易出錯,而且不建議在程式代碼中 /clr 。 這是因為在 DLL 的某些 Managed 部分執行之前,不保證 DLL 的數據區段初始化。 參考具有 #using 指示詞的元數據。

型別可視性

原生型態預設為 privateprivate在 DLL 外部看不到原生類型。 藉由新增 public 至這些類型來解決此錯誤。

浮點和對齊問題

__controlfp Common Language Runtime 不支援。 如需詳細資訊,請參閱_control87_controlfp__control87_2。 CLR 也不尊重 align

COM 初始化

Common Language Runtime 會在模組初始化時自動初始化 COM(當 COM 自動初始化時,它會以 MTA 完成)。 因此,明確初始化 COM 會產生傳回碼,指出 COM 已經初始化。 當 CLR 已將 COM 初始化為另一個線程模型時,嘗試使用一個線程模型明確地初始化 COM,可能會導致您的應用程式失敗。

Common Language Runtime 預設會以 MTA 的形式啟動 COM;使用 /CLRTHREADATTRIBUTE (設定 CLR 線程屬性) 來修改 COM 模型。

效能問題

當產生至 MSIL 的原生C++方法間接呼叫時,您可能會看到效能降低(透過虛擬函式呼叫或使用函式指標)。 若要深入瞭解,請參閱 Double Thunking

當您從原生移至 MSIL 時,您會發現工作集的大小會增加。 之所以增加,是因為 Common Language Runtime 提供許多功能,以確保程式能夠正確執行。 /clr如果您的應用程式未正確執行,您可能想要啟用預設編譯程式警告 (層級 1 和 3) C4793

程式在關機時當機

在某些情況下,CLR 可以在 Managed 程式代碼完成執行之前關閉。 std::set_terminate使用和 SIGTERM 可能會導致關機。 如需詳細資訊,請參閱 signal 常數set_terminate

使用新的 Visual C++ 功能

在應用程式編譯、鏈接和執行之後,您就可以在任何使用 編譯的 /clr模組中使用 .NET 功能。 如需詳細資訊,請參閱 Component Extensions for Runtime Platforms

如需 Visual C++ 中 .NET 程式設計的詳細資訊,請參閱:

另請參閱

混合 (原生和 Managed) 組件