一隻.NET寫的排程程式在Windows 2008 x64 OS執行,在連線Oracle資料庫時出現錯誤:

System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
   at System.Data.OracleClient.OracleInternalConnection.Enlist(String userName, String password, String serverName, Transaction transaction, Boolean manualEnlistment)
   at System.Data.OracleClient.OracleInternalConnection.Activate(Transaction transaction)
   at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
   at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.OracleClient.OracleConnection.Open()

依過去經驗,推測原因為該.NET程式的平台目標(Platform Target)被標註為Any CPU,在x64 Windows平台執行時會在64位元程序(Process)中執行,當它要引用Oracle Client DLL時,在該主機上找不到對應的64位元版DLL,試圖載入32位元版,因而產生錯誤。

要消除茶包,只需將平台目標設為x86重新編譯專案,強迫程式永遠使用32位元程序執行,問題即告排除。不過心生疑問,有沒有方法可以立刻查出某個exe/dll的目標平台被編譯成Any CPU, x86或是x64?

找到.NET Framework SDK中的一個工具程式: CorFlags.exe。CorFlags.exe不但可查詢.NET組件的平台目標設定,甚至能直接修改設定,省去重新編譯的工夫。

先透過實驗觀察不同平台目標組件的旗標。在Visual Studio中依序調整PlatformTarget為Any CPU, x86及x64,分別編譯成BuildTargetAny.exe, BuildTargetX86.exe, BuildTargetX64.exe三個執行檔。

再使用corflags buildtarget*.exe的方法檢視相關旗標,得到結果如下:

H:\Lab\BuildTarget\bin>corflags BuildTargetAny.exe
Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  4.0.30319.1
Copyright (c) Microsoft Corporation.  All rights reserved.

Version   : v2.0.50727
CLR Header: 2.5
PE        : PE32
CorFlags  : 1
ILONLY    : 1
32BIT     : 0
Signed    : 0

H:\Lab\BuildTarget\bin>corflags BuildTargetx86.exe
Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  4.0.30319.1
Copyright (c) Microsoft Corporation.  All rights reserved.

Version   : v2.0.50727
CLR Header: 2.5
PE        : PE32
CorFlags  : 3
ILONLY    : 1
32BIT     : 1
Signed    : 0

H:\Lab\BuildTarget\bin>corflags BuildTargetx64.exe
Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  4.0.30319.1
Copyright (c) Microsoft Corporation.  All rights reserved.

Version   : v2.0.50727
CLR Header: 2.5
PE        : PE32+
CorFlags  : 1
ILONLY    : 1
32BIT     : 0
Signed    : 0

PE, CorFlags, IONLY, 32BIT等旗標的意義可以參考這篇討論。若要將編譯成Any CPU的程式目標平台改為限定x86,可使用以下指令:

CorFlags /32BIT+ BuildTargetAny.exe

將參數改為/32BIT-則可以再還原回Any CPU。至於純x64目標平台的程式由於PE不同(為PE32+,與Any CPU, x86不同),故無法直接使用CorFlags切換,必須重新編譯。


Comments

# by 小黑

黑大,好厲害,怎麼都這麼精準搜尋的到, 不知道都是打那些關鍵字搜尋的阿?

Post a comment