1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

C++/CLIでWindows APIを呼び出す時に、GetLastError()とMarshal::GetLastWin32Error()のどちらを使用すべきか。

Posted at

もう古代の技術の話題ですが。

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()で最後のエラーコードを取得する。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?