もう古代の技術の話題ですが。
TL;DR
- C++/CLIから直接Windows APIを呼び出す場合は、
Marshal::GetLastWin32Error()
のほうが便利 - C++/CLIの外のライブラリからWindows API呼び出す、または
SetLastError()
する場合は、GetLastError()
を使用しなければならない。
Windows APIをC++/CLIから直接呼び出した場合
C++/CLIから直接呼び出と、P/Invoke(DLLImport)のコードが生成される。
ILを確認すると、C#の下記に相当するコードになる。
[DllImport("", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
[MethodImpl(MethodImplOptions.Unmanaged)]
[SuppressUnmanagedCodeSecurity]
internal unsafe static extern void* CreateFileW(char* P_0, uint P_1, uint P_2, _SECURITY_ATTRIBUTES* P_3, uint P_4, uint P_5, void* P_6);
リンカーの/CLRSUPPORTLASTERRORオプションでは、規定でSetLastError = true
が設定されるようになっている。
そのため、Marshal::GetLastWin32Error()
でエラーコードを参照でき、gcnew System::ComponentModel::Win32Exception()
でも最後のエラーコードが使用される。
C++/CLIからGetLastError()
を呼び出しても、おそらく動作はするはずだが望ましくない(はず)。
C++/CLIの外のライブラリからWindows API呼び出した場合
DLLやスタティックリンクライブラリからWindows APIを呼び出す、またはその中でSetLastError()
を呼び出しても、当然P/Invoke(DLLImport)のコードが生成されない。
そのため、CLRからはいつSetLastError()
されたかわからないので、明示的にGetLastError()
を呼び出す必要がある。
そもそも、ライブラリの外でGetLastError()
をする設計は望ましくない。
個人的な方針
Windows APIをC++/CLIから直接呼び出して最後のエラーコードを取得するケースがほとんどで、"C++/CLI"を使っているのだから、理由がなければMarshal::GetLastWin32Error()
で最後のエラーコードを取得する。