Marshal.GetLastWin32Error()

L

Larry Smith

Hi there,

Does anyone know if this (example) is safe:

[DllImport("user32.dll", SetLastError = true)]
internal static extern int GetWindowRect(IntPtr hWnd, ref RECT
rect);

int rc = GetWindowRect(hWnd, ref rect);
if (rc == 0)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error");
}

My concern is the call to "Marshal.GetLastWin32Error()". Can the value
returned by this function be modified by the call to the exception
constructor itself. For instance, could construction of the "Error" string
overwrite "Marshal.GetLastWin32Error()" on failure given that it might also
call into the WinAPI. This would be a problem in C++ for instance where you
can't depend on the order of the parameters being passed (i.e., you can't
reliably pass "GetLastError()" as the first arg since the 2nd.arg might be
evaluated first - on failure it would then overwrite the first arg)
 
N

Nicholas Paldino [.NET/C# MVP]

Larry,

The only way that GetLastWin32Error is going to return a different value
is if you use another call to unmanaged code. You should store the error if
you are going to perform an operation which could possibly change it, and
you need it for later.

I am curious, why are you passing an error string or the last error to
the Win32Exception class? If you use the default constructor, it should get
the value of the last win 32 error and also create the appropriate exception
message.

Hope this helps.
 
L

Larry Smith

Thanks for the feedback:
The only way that GetLastWin32Error is going to return a different value
is if you use another call to unmanaged code. You should store the error
if you are going to perform an operation which could possibly change it,
and you need it for later.

I won't be calling unmanaged code directly. My concern are calls that .NET
itself makes. Those calls will invoke "SetLastError()" in the WinAPI but
does this affect "Marshal.GetLastWin32Error()" for clients (i.e., me). Note
that I can always save the result before throwing the exception (passing
this value to the constructor) but I'd like to know what the rules are.
I am curious, why are you passing an error string or the last error to the
Win32Exception class? If you use the default constructor, it should get
the value of the last win 32 error and also create the appropriate
exception message.

I'm still experimenting but I want to capture context info at the time of
call (the parameters that caused the failure for instance). Take this as a
possible solution for example (which I'm still considering):

class Win32LastError : Win32Exception
{
public Win32LastError(string messageEx)
{
m_MessageEx = messageEx;
}

public string MessageEx
{
get
{
return m_MessageEx;
}
}

private string m_MessageEx;
}

When the base class' default constructor is called, could the last error
have already been overwritten during construction of the "messageEx"
parameter itself (in the above constructor). It relies on the WinAPI behind
the scenes so it could potentially change the last error before the base
class constructor even starts (or so I'm speculating). This would be
particularly true if a non-trivial expression is used to create the string
in the first place (at the point of call). Note that this won't involve
unmanaged code however.
 
N

Nicholas Paldino [.NET/C# MVP]

Larry,

The GetLastWin32Error method will only return the value of GetLastError
for P/Invoke calls, not for CLR internal calls (as the documentation
states). Because of this, you only have to worry about the code being
changed if another call on the same thread makes another call through the
P/Invoke layer.
 
L

Larry Smith

The GetLastWin32Error method will only return the value of GetLastError
for P/Invoke calls, not for CLR internal calls (as the documentation
states). Because of this, you only have to worry about the code being
changed if another call on the same thread makes another call through the
P/Invoke layer.

I just assumed as much and the docs basically say so but I didn't want to
get tripped up with subtle problems later (since I'm relatively new to
..NET). Thanks very much for your help.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top