int vs IntPtr when you have a handle?
Asked Answered
J

1

17

First a background question:

In general, what is the difference between int and IntPtr? My guess is that it is an actual object rather than a value like an int or byte is. Assuming that is true:

So they are not the same. Yet I see handles represented as both.

  1. IntPtr: Control.Handle
  2. int (or uint): A PInvoke can be setup to return an int and it works just fine:

    [DllImport("coredll.dll", SetLastError = true)]
    public static extern int GetForegroundWindow();
    private string GetActiveWindow()
    {
        const int nChars = 256;
        int handle = 0;
        StringBuilder Buff = new StringBuilder(nChars);
    
        handle = CoreDLL.GetForegroundWindow();
    
        if (CoreDLL.GetWindowText(handle, Buff, nChars) > 0)
        {
            return Buff.ToString();
        }
    
        return "";
    }
    

So, int vs IntPtr? Does it matter for handles? Can you use either?

Justify answered 30/11, 2010 at 17:23 Comment(0)
B
39

int is 32 bits long. IntPtr is as long as a pointer for your architecture. Therefore, a pointer can be stored into an int only on 32 bit systems, while it can always be stored in an IntPtr.

Notice that your "int as a return value" example does not use an int to hold a pointer, but just to hold a numeric value. This does not mean that an int is automatically the correct size though: the author of that P/Invoke signature should have gone to the documentation for GetForegroundWindow and see that it returns a HWND.

Then, from windef.h in the Platform SDK (or this MSDN page) we can see that a HWND is a HANDLE which is a PVOID which is... a pointer!

Therefore, as far as I can tell, that signature is wrong, as the size of the return value of GetForegroundWindow depends on the architecture. Thus, it should also be an IntPtr.

Update:

While it can be inferred from the above, I think it's worthwhile to explicitly point out that:

  • Erroneously using int instead of IntPtr in 32-bit applications will never cause a problem, even if they run on 64-bit Windows; since most applications are 32-bit at this point in time, this will let you get away such mistakes very often.
  • Erroneously using int instead of IntPtr in 64-bit applications is not guaranteed to cause problems, since it is quite possible that in practice the values being encountered will fit in the 32 bits of the int. This further lessens the probability that a mistake will manifest as an application error.

Therefore, for an error to actually manifest there are three conditions that have to be satisfied at the same time:

  1. An int is used where an IntPtr should be.
  2. The executable image is 64-bit.
  3. A value returned by some PInvoke call and stored as an int is actually larger than 32 bits.
Bdellium answered 30/11, 2010 at 17:24 Comment(3)
if you run with top down memory allocation then you can guarantee condition 3 which is very useful when developingCocainize
Your post is life-saver Jon. I wish I could do something to draw more attention into it. I had hit rock bottom with a component that was behaving erratically and your insight placed me on the right track! You made my day. No. My week. Possibly my entire month to say the least. Thanks again! P.S.: Here's an example of how things can go south with int vs IntPtr: https://mcmap.net/q/743616/-global-keyboard-hook/…Stream
@Jon, I think that Vaccano has using this in an embedded system (may be wince, always 32 bits) [coredll.dll].Bourbon

© 2022 - 2024 — McMap. All rights reserved.