Pete R

I am trying to figure out P/Invoke best practices when making calls to the Win32 API. It's amazing Microsoft doesn't seem to have definitive documentation on this, and the pinvoke.net Wiki seems to be the most useful source available. If there's a better source, please clue me in. In any case the interop signatures don't seem to be consistent in their use of IntPtr vs HandleRef, and there's nary a mention of deriving things from SafeHandle. For example, the signature given for SetForegroundWindow is:


[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);

Yet in sample code elsewhere from people who are major contributors to the pinvoke.net Wiki (e.g. Adam Nathan) I see

[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(HandleRef hWnd);

As with the lack of [MarshalAs(UnmanagedType.Bool)] in the second version it's hard to find a lot of consistency. Shouldn't virtually everything at least use HandleRef instead of IntPtr Correct me if I'm wrong on any of this, but I suppose I could either use the first version with a GC.KeepAlive call:

SetForegroundWindow(hWnd);
GC.KeepAlive(hWnd);

to ensure the GC doesn't toss out hWnd too early, or the HandleRef version. But in using HandleRef for a window handle, I've seen 1) new HandleRef(this, hWnd), 2) new HandleRef(null, hWnd), and 3) new HandleRef(hWnd, hWnd).

The first one is fairly obvious, tying the life of the IntPtr hWnd to this, but what if I make the call from a static class and can't use this The second version seems dicey to me because I don't know what the lifetime of null would be. It seems to provide no guarantee that the GC won't collect hWnd before the call is done. In the third version, if there is no reference to hWnd after the call, does it guarantee the lifetime of hWnd for the duration of the call

Use of SafeHandle-derived classes is even more confusing with window handles. It seems one rarely "owns" window handles unless you call CreateWindow. Anyway, comments on any of the above are welcome.

Pete



Re: Visual C# General P/Invoke signatures and IntPtr vs HandleRef (vs SafeHandle)

BinaryCoder

1. SafeHandle is preferred over IntPtr. (I am not sure how to deal with the handle closing issue you mentioned. Maybe someone else can chime in.)

2. MarshalAs(UnmanagedType.Bool) is a good idea because there are several types of booleans and the rules for which one is used by default are context-sensitive and confusing. In fact, FxCop has a rule that warns when the attribute is not used. I think it is technically required for your example. See Default Marshaling for Boolean Types (http://msdn2.microsoft.com/en-us/library/t2t3725f.aspx).

Note that I have found that many of the PInvoke signatures on pinvoke.net to be questionable. I usually use the site to double-check my work or help me out with constant values, but I do not rely on it.





Re: Visual C# General P/Invoke signatures and IntPtr vs HandleRef (vs SafeHandle)

Peter Ritchie

When you're dealing with a "handle" resource (i.e. one that must be created and destroyed) you should always use SafeHandle.

Use IntPtr when the content of the data is irrelevant to the application, i.e. is opaque data.






Re: Visual C# General P/Invoke signatures and IntPtr vs HandleRef (vs SafeHandle)

Pete R

Thanks for the link. It's good to see I'm not the only one who wonders about the consistency or quality of information on pinvoke.net. It boggles my mind that there is official MSDN documentation for the FCL and the Win32 API, but not the P/Invoke signatures. In fact, there should be an interop library complete with necessary SafeHandle types available for download, but I'd settle for good documentation and example code.





Re: Visual C# General P/Invoke signatures and IntPtr vs HandleRef (vs SafeHandle)

Pete R

Hi Peter,

What if I'm not the one who created or is obligated to destroy the handle It sounds like you are saying one should use SafeHandle for any interop call involving handles. If so, how would one do this for typical calls involving window handles For example, let's assume Calculator is running, and I want to find the window and bring it to the foreground using FindWindow and SetForegroundWindow. Should I use IntPtrs or SafeHandles If the latter can you give the example code using a SafeWindowHandle derived from SafeHandle Thanks,

Pete





Re: Visual C# General P/Invoke signatures and IntPtr vs HandleRef (vs SafeHandle)

Peter Ritchie

If some other code is "giving" you a handle, how will it know to destroy it If it's a property of another object, it should be that object's responsibility to destroy it. Otherwise, if you get the handle as the return of a method call, it's almost always the responsibility of the caller to destroy it.






Re: Visual C# General P/Invoke signatures and IntPtr vs HandleRef (vs SafeHandle)

Pete R

I think I get the gist of what you're saying, but let's pretend I'm really thick-headed and need to see an example. Wink In the given example of finding the Calculator window and setting it to the foreground, would it be correct to use IntPtr or SafeHandle I didn't create the Calculator window and don't own the handle, right





Re: Visual C# General P/Invoke signatures and IntPtr vs HandleRef (vs SafeHandle)

Peter Ritchie

Pete R wrote:
I think I get the gist of what you're saying, but let's pretend I'm really thick-headed and need to see an example. In the given example of finding the Calculator window and setting it to the foreground, would it be correct to use IntPtr or SafeHandle I didn't create the Calculator window and don't own the handle, right

It would depend on how you're getting the calculator window handle... If you're enumerating all the window handles with EnumWindow, for example, it would be a very bad thing to close that handle...






Re: Visual C# General P/Invoke signatures and IntPtr vs HandleRef (vs SafeHandle)

Pete R

OK, so I want to be sure I don't close that handle. In that case SafeHandle seems overkill, since I'm not responsible for releasing the unmanaged resource, and the point of SafeHandle is to ensure that that happens under all conditions. So I have IntPtr or HandleRef. If I call SetForegroundWindow with an IntPtr argument, the GC may collect the IntPtr before the call completes. I can stop that with GC.KeepAlive, but according to MSDN the "preferred" way is to use HandleRef. So let's assume I have a static class, and I've gotten the handle via EnumWindows, and I'm going to call SetForegroundWindow on it. I don't have a this pointer, so I call SetForegroundWindow(new HandleRef( , hWnd)) where is what Null hWnd Some other random object I know is going to live past the call





Re: Visual C# General P/Invoke signatures and IntPtr vs HandleRef (vs SafeHandle)

Peter Ritchie

HandleRef is for making sure that a managed object from which you obtained an unmanaged handle doesn't get collected before you're done with the handle. For example:

Code Block

MyObject myObject = new MyObject();

IntPtr handle = myObject.GetHandle();

// myObject is eligable for collection now

NativeMethods.SomeNativeFunction(handle); // at this point if myObject had been collected the value in "handle" will be invalid.

If you're getting your handle from a native method (i.e. through PInvoke or as an argument in your EnumWindows callback) you don't need to use HandleRef, all arguments passed through a PInvoke call won't be collected until the call returns.






Re: Visual C# General P/Invoke signatures and IntPtr vs HandleRef (vs SafeHandle)

Pete R

OK, that actually makes sense. I wish the documentation was as clear. Thanks.