c++dllvbscriptgetlasterror

WinAPI - GetLastError always returns 0 when called via a COM ATL DLL


In my Windows API wrapper ATL dll, I have exposed GetLastError to COM for Windows API error handling.

It is implemented as below:

STDMETHODIMP CWinAPI::WinAPI_GetLastError(int *Result) {

    *Result = (int)GetLastError();

    return S_OK;
}

When I use it from VBScript like:

Dim WINAPI: Set WINAPI = WScript.CreateObject("WinAPIWrapperLib.WINAPI")

WINAPI.WinAPI_ShellExecute NULL, "", "NonExistentFile.exe", "", "", 1
WScript.Echo CStr(WINAPI.WinAPI_GetLastError)

This must generate the ERROR_FILE_NOT_FOUND error, but when I call this windows API function from my wrapper dll via VBScript, it always returns ERROR_SUCCESS.

But when I add following lines to my implementation for WinAPI_ShellExecute like this:

DWORD ErrorMessageID = ::GetLastError();

wchar_t ErrorID[1024];

swprintf_s(ErrorID, 1024, L"%d", ErrorMessageID);

MessageBox(nullptr, (LPCWSTR)&ErrorID, L"GetLastError", MB_OK | MB_ICONERROR | MB_DEFBUTTON1);

It correctly generates the error ERROR_FILE_NOT_FOUND.

I like to know what goes wrong with GetLastError.

Thanks in Advance.


Solution

  • Remarks

    Functions executed by the calling thread set this value by calling the SetLastError function. You should call the GetLastError function immediately when a function's return value indicates that such a call will return useful data. That is because some functions call SetLastError with a zero when they succeed, wiping out the error code set by the most recently failed function.

    The problem is: you could not guarantee, that GetLastError is called immediately after ShellExecute. There is much going on between that calls - COM marshalling, VBScript calls, etc that most certainly affects thread last error flag. In fact you should not use GetLastError in the VBScript altogether:

    Visual Basic: Applications should call err.LastDllError instead of GetLastError.