Results 1 to 11 of 11

Thread: [RESOLVED] IntPtr vs HandleRef

  1. #1

    Thread Starter
    Fanatic Member BlindSniper's Avatar
    Join Date
    Jan 2011
    Location
    South Africa
    Posts
    865

    Resolved [RESOLVED] IntPtr vs HandleRef

    Hello all,
    I'm making a wrapper DLL for my Windows API functions that I use a lot. Now anyone who has worked with windows API knows that probably 80% of the windows API calls use one or more handles as argument(s). Now I've read that sometimes GC will collect the IntPtr and then your PInvoke will fail.
    I've got a few questions.

    #1 Why/when use HandleRef Over IntPtr
    #2 What is the correct method of declaring a HandleRef ( what is the wrapper ?)

    And I have a few other questions.
    #3 You can import a external function using the DLLImport Attribute or using a 'Declare' and 'lib' Which one is the best/correct ? (to me the DLLImport attribute looks so much more legit than the 'declare' and 'lib')
    #4 I Want to create a Wrapper for SendMessage But It can have various return data types (and probably various argument datatypes) Is it correct If I just make the return type Object ? Or would I need to make a class just for SendMessage ?

    EDIT #5 What is the difference between Intptr and a normal Integer ? it seems like they both just contain numeric data ?

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: IntPtr vs HandleRef

    1. HandleRef is not really an alternative to an IntPtr. A HandleRef itself contains an IntPtr, as well as a managed reference to the object that that IntPtr refers to. As the documentation says, you would use a HandleRef when that object is not referenced anywhere else in managed code. If there are no references to a managed object then that object is eligible for garbage collection, so a HandleRef exists simply to create a managed reference, thus preventing the object being garbage collected.
    2. You invoke the constructor with the New keyword, just as you do with a class, and pass the object and the IntPtr.
    3. 'Declare' is a VB6 holdover. DllImport is the .NET way to call an unmanaged function.
    4. For the different parameter types, you should overload the method. For the different return types, you could just declare a single method with return type Object, but I would tend to declare multiple methods with different names and return types as appropriate.
    5. An IntPtr is specifically intended to store a value that represents a handle or a pointer, while an Integer stores things like counts, etc. You would never, for example, multiply two IntPtrs together. You could use Integers all the time but it's a metter of intent.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  3. #3
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: IntPtr vs HandleRef

    At some point however a function only allows a HandleRef as a parameter and not the IntPtr. Just go with IntPtr as long the parameters work, and as soon the GetLastError returns a "invalid parameter" error you might have to use a HandleRef instead.

    Since API's don't continue until the function completed, a handleref is usually useless. A few functions that require a handleref:
    Code:
        <Runtime.InteropServices.DllImport("user32.dll", EntryPoint:="GetWindowLong")> _
        Private Shared Function GetWindowLongPtr32(ByVal hWnd As Runtime.InteropServices.HandleRef, ByVal nIndex As Integer) As Long
        End Function
        <Runtime.InteropServices.DllImport("user32.dll", EntryPoint:="GetWindowLongPtr")> _
        Private Shared Function GetWindowLongPtr64(ByVal hWnd As Runtime.InteropServices.HandleRef, ByVal nIndex As Integer) As Long
        End Function
        Private Declare Function GetWindowRect Lib "user32" (ByVal hWnd As System.Runtime.InteropServices.HandleRef, ByRef lpRect As API.WRECT) As Boolean
        Private Declare Function GetClientRect Lib "user32" (ByVal hWnd As System.Runtime.InteropServices.HandleRef, ByRef lpRect As API.WRECT) As Boolean

  4. #4

    Thread Starter
    Fanatic Member BlindSniper's Avatar
    Join Date
    Jan 2011
    Location
    South Africa
    Posts
    865

    Re: IntPtr vs HandleRef

    Thank you very much for the replies
    I was thinking about sendmessage.
    Would it work if I created a class(of returntype)

    like
    Code:
    Class SendMessage(Of returntype)
    
        Function sendmessage(...) As returntype
    
        End Function
    
    End Class
    Assuming that Function SendMessage is the wrapper to the Windows API ?
    Last edited by BlindSniper; Apr 3rd, 2011 at 06:56 AM.

  5. #5
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: IntPtr vs HandleRef

    Sure it would work, but there are ALOT of messages. There are WM_ messages, but also for buttons, textboxes, checkboxes, radiobuttons, listview, listboxes, pictureboxes, alot. If you were to change all these messages to functions/subs, it would become an ENORMOUS class.

    I recommend storing all these messages in an enumeration and keep all regular non-argument messages in a single function, and the more argument heavy functions (get text) in a separate one.

    I added all functions in the start, but the message list is simply too large. I did make separate structures for the SendKey commands though.
    vb Code:
    1. Public Class WM
    2.         Public Enum SC 'System Commands
    3.             CLOSE = &HF060
    4.             CONTEXTHELP = &HF180
    5.             CDEFAULT = &HF160
    6.             HOTKEY = &HF150
    7.             HSCROLL = &HF080
    8.             ISSECURE = &H1
    9.             KEYMENU = &HF100
    10.             MAXIMIZE = &HF030
    11.             MINIMIZE = &HF020
    12.             MONITORPOWER = &HF170
    13.             MouseMenu = &HF090
    14.             MOVE = &HF010
    15.             NEXTWINDOW = &HF040
    16.             PREVWINDOW = &HF050
    17.             RESTORE = &HF120
    18.             SCREENSAVE = &HF140
    19.             Size = &HF000
    20.             TASKLIST = &HF130
    21.             VSCROLL = &HF070
    22.         End Enum
    23.  
    24.         Public Enum msg As UInteger
    25.             USER = &H400&
    26.             ACTIVATE = &H6
    27.             ACTIVATEAPP = &H1C
    28.             ASKCBFORMATNAME = &H30C
    29.             CANCELJOURNAL = &H4B
    30.             CANCELMODE = &H1F
    31.             CHANGECBCHAIN = &H30D
    32.             Chr = &H102
    33.             CHARTOITEM = &H2F
    34.             CHILDACTIVATE = &H22
    35.             CHOOSEFONT_GETLOGFONT = (USER + 1)
    36.             CHOOSEFONT_SETFLAGS = (USER + 102)
    37.             CHOOSEFONT_SETLOGFONT = (USER + 101)
    38.             CLEAR = &H303
    39.             CLOSE = &H10
    40.             Command = &H111
    41.             COMMNOTIFY = &H44 ' no longer suported
    42.             COMPACTING = &H41
    43.             COMPAREITEM = &H39
    44.             CONVERTREQUESTEX = &H108
    45.             Copy = &H301
    46.             COPYDATA = &H4A
    47.             CREATE = &H1
    48.             CTLCOLORBTN = &H135
    49.             CTLCOLORDLG = &H136
    50.             CTLCOLOREDIT = &H133
    51.             CTLCOLORLISTBOX = &H134
    52.             CTLCOLORMSGBOX = &H132
    53.             CTLCOLORSCROLLBAR = &H137
    54.             CTLCOLORSTATIC = &H138
    55.             CUT = &H300
    56.             DDE_FIRST = &H3E0
    57.             DDE_ACK = (DDE_FIRST + 4)
    58.             DDE_ADVISE = (DDE_FIRST + 2)
    59.             DDE_DATA = (DDE_FIRST + 5)
    60.             DDE_EXECUTE = (DDE_FIRST + 8)
    61.             DDE_INITIATE = (DDE_FIRST)
    62.             DDE_LAST = (DDE_FIRST + 8)
    63.             DDE_POKE = (DDE_FIRST + 7)
    64.             DDE_REQUEST = (DDE_FIRST + 6)
    65.             DDE_TERMINATE = (DDE_FIRST + 1)
    66.             DDE_UNADVISE = (DDE_FIRST + 3)
    67.             DEADCHAR = &H103
    68.             DELETEITEM = &H2D
    69.             DESTROY = &H2
    70.             DESTROYCLIPBOARD = &H307
    71.             DEVMODECHANGE = &H1B
    72.             DRAWCLIPBOARD = &H308
    73.             DRAWITEM = &H2B
    74.             DROPFILES = &H233
    75.             ENABLE = &HA
    76.             ENDSESSION = &H16
    77.             ENTERIDLE = &H121
    78.             ENTERMENULOOP = &H211
    79.             ERASEBKGND = &H14
    80.             EXITMENULOOP = &H212
    81.             FONTCHANGE = &H1D
    82.             GETFONT = &H31
    83.             GETDLGCODE = &H87
    84.             GETHOTKEY = &H33
    85.             GETMINMAXINFO = &H24
    86.             GETTEXT = &HD
    87.             GETTEXTLENGTH = &HE
    88.             HOTKEY = &H312
    89.             HSCROLL = &H114
    90.             HSCROLLCLIPBOARD = &H30E
    91.             ICONERASEBKGND = &H27
    92.             IME_CHAR = &H286
    93.             IME_COMPOSITION = &H10F
    94.             IME_COMPOSITIONFULL = &H284
    95.             IME_CONTROL = &H283
    96.             IME_ENDCOMPOSITION = &H10E
    97.             IME_KEYDOWN = &H290
    98.             IME_KEYLAST = &H10F
    99.             IME_KEYUP = &H291
    100.             IME_NOTIFY = &H282
    101.             IME_SELECT = &H285
    102.             IME_SETCONTEXT = &H281
    103.             IME_STARTCOMPOSITION = &H10D
    104.             INITDIALOG = &H110
    105.             INITMENU = &H116
    106.             INITMENUPOPUP = &H117
    107.             KEYDOWN = &H100
    108.             KEYFIRST = &H100
    109.             KEYLAST = &H108
    110.             KEYUP = &H101
    111.             KILLFOCUS = &H8
    112.             LBUTTONDBLCLK = &H203
    113.             LBUTTONDOWN = &H201
    114.             LBUTTONUP = &H202
    115.             MBUTTONDBLCLK = &H209
    116.             MBUTTONDOWN = &H207
    117.             MBUTTONUP = &H208
    118.             MDIACTIVATE = &H222
    119.             MDICASCADE = &H227
    120.             MDICREATE = &H220
    121.             MDIDESTROY = &H221
    122.             MDIGETACTIVE = &H229
    123.             MDIICONARRANGE = &H228
    124.             MDIMAXIMIZE = &H225
    125.             MDINEXT = &H224
    126.             MDIREFRESHMENU = &H234
    127.             MDIRESTORE = &H223
    128.             MDISETMENU = &H230
    129.             MDITILE = &H226
    130.             MEASUREITEM = &H2C
    131.             MENUCHAR = &H120
    132.             MENUSELECT = &H11F
    133.             MOUSEACTIVATE = &H21
    134.             MOUSEFIRST = &H200
    135.             MOUSELAST = &H209
    136.             MOUSEMOVE = &H200
    137.             MOVE = &H3
    138.             NCACTIVATE = &H86
    139.             NCCALCSIZE = &H83
    140.             NCCREATE = &H81
    141.             NCDESTROY = &H82
    142.             NCHITTEST = &H84
    143.             NCLBUTTONDBLCLK = &HA3
    144.             NCLBUTTONDOWN = &HA1
    145.             NCLBUTTONUP = &HA2
    146.             NCMBUTTONDBLCLK = &HA9
    147.             NCMBUTTONDOWN = &HA7
    148.             NCMBUTTONUP = &HA8
    149.             NCMOUSEMOVE = &HA0
    150.             NCPAINT = &H85
    151.             NCRBUTTONDBLCLK = &HA6
    152.             NCRBUTTONDOWN = &HA4
    153.             NCRBUTTONUP = &HA5
    154.             NEXTDLGCTL = &H28
    155.             NULL = &H0
    156.             PAINT = &HF
    157.             PAINTCLIPBOARD = &H309
    158.             PAINTICON = &H26
    159.             PALETTECHANGED = &H311
    160.             PALETTEISCHANGING = &H310
    161.             PARENTNOTIFY = &H210
    162.             PASTE = &H302
    163.             PENWINFIRST = &H380
    164.             PENWINLAST = &H38F
    165.             POWER = &H48
    166.             Print = &H317
    167.             PSD_ENVSTAMPRECT = (USER + 5)
    168.             PSD_FULLPAGERECT = (USER + 1)
    169.             PSD_GREEKTEXTRECT = (USER + 4)
    170.             PSD_MARGINRECT = (USER + 3)
    171.             PSD_MINMARGINRECT = (USER + 2)
    172.             PSD_PAGESETUPDLG = (USER)
    173.             PSD_YAFULLPAGERECT = (USER + 6)
    174.             QUERYDRAGICON = &H37
    175.             QUERYENDSESSION = &H11
    176.             QUERYNEWPALETTE = &H30F
    177.             QUERYOPEN = &H13
    178.             QUEUESYNC = &H23
    179.             QUIT = &H12
    180.             RBUTTONDBLCLK = &H206
    181.             RBUTTONDOWN = &H204
    182.             RBUTTONUP = &H205
    183.             RENDERALLFORMATS = &H306
    184.             RENDERFORMAT = &H305
    185.             SETCURSOR = &H20
    186.             SETFOCUS = &H7
    187.             SETFONT = &H30
    188.             SETHOTKEY = &H32
    189.             SETREDRAW = &HB
    190.             SETTEXT = &HC
    191.             Size = &H5
    192.             SIZECLIPBOARD = &H30B
    193.             SPOOLERSTATUS = &H2A
    194.             SYSCHAR = &H106
    195.             SYSCOLORCHANGE = &H15
    196.             SYSCOMMAND = &H112
    197.             SYSDEADCHAR = &H107
    198.             SYSKEYDOWN = &H104
    199.             SYSKEYUP = &H105
    200.             SHOWWINDOW = &H18
    201.             Timer = &H113
    202.             TIMECHANGE = &H1E
    203.             UNDO = &H304
    204.             VKEYTOITEM = &H2E
    205.             VSCROLL = &H115
    206.             VSCROLLCLIPBOARD = &H30A
    207.             WINDOWPOSCHANGED = &H47
    208.             WINDOWPOSCHANGING = &H46
    209.             WININICHANGE = &H1A
    210.         End Enum 'Window Messages
    211.  
    212.         Public Shared Function GETTEXTLENGTH(ByVal hwnd As IntPtr) As Integer
    213.             Return DefWindowProc(hwnd, 14, 0, 0) + 1
    214.         End Function
    215.         Public Shared Property TEXT(ByVal hwnd As IntPtr) As String
    216.             Get
    217.                 Dim length As Integer = GETTEXTLENGTH(hwnd)
    218.                 Dim Handle As IntPtr = Runtime.InteropServices.Marshal.AllocHGlobal(length)
    219.                 DefWindowProc(hwnd, 13, length, Handle)
    220.                 Return Runtime.InteropServices.Marshal.PtrToStringAnsi(Handle)
    221.             End Get
    222.             Set(ByVal value As String)
    223.                 DefWindowProc(hwnd, &HC, IntPtr.Zero, Runtime.InteropServices.Marshal.StringToHGlobalAnsi(value))
    224.             End Set
    225.         End Property
    226.         Public Shared Property FONT(ByVal hwnd As IntPtr) As System.Drawing.Font
    227.             Get
    228.                 Return System.Drawing.Font.FromHfont(SendMessage(hwnd, msg.GETFONT))
    229.             End Get
    230.             Set(ByVal value As System.Drawing.Font)
    231.                 SendMessage(hwnd, msg.SETFONT, value.ToHfont, True)
    232.             End Set
    233.         End Property
    234.         Public Shared Function CLOSE(ByVal hwnd As IntPtr) As Integer
    235.             Return DefWindowProc(hwnd, msg.CLOSE, 0, 0)
    236.         End Function
    237.         Public Shared Function DESTROY(ByVal hwnd As IntPtr) As Integer
    238.             Return DefWindowProc(hwnd, msg.DESTROY, 0, 0)
    239.         End Function
    240.         Public Shared Function CLEAR(ByVal hwnd As IntPtr) As Integer
    241.             Return DefWindowProc(hwnd, msg.CLEAR, 0, 0)
    242.         End Function
    243.         Public Shared Function UNDO(ByVal hwnd As IntPtr) As Integer
    244.             Return DefWindowProc(hwnd, msg.UNDO, 0, 0)
    245.         End Function
    246.  
    247.         Public Shared Function SYSCOMMAND(ByVal hwnd As IntPtr, ByVal command As SC, Optional ByVal lparam As Integer = 0) As Boolean
    248.             Return DefWindowProc(hwnd, WM.msg.SYSCOMMAND, command, lparam)
    249.         End Function
    250.         Public Shared Function SYSCOMMAND(ByVal hwnd As IntPtr, ByVal command As SC, ByVal x As Short, ByVal y As Short) As Boolean
    251.             Return DefWindowProc(hwnd, WM.msg.SYSCOMMAND, command, New DWORD(x, y).Integer1)
    252.         End Function
    253.     End Class

    Don't mind the DefWindowProc, I named it like that by mistake in the beginning
    If you really want everything in your class, make subclasses with a "msg" enum inside.

  6. #6

    Thread Starter
    Fanatic Member BlindSniper's Avatar
    Join Date
    Jan 2011
    Location
    South Africa
    Posts
    865

    Re: IntPtr vs HandleRef

    Cool, Thanks I'll Post My SendMessage Implimentation When i'm Done.

  7. #7

    Thread Starter
    Fanatic Member BlindSniper's Avatar
    Join Date
    Jan 2011
    Location
    South Africa
    Posts
    865

    Re: IntPtr vs HandleRef

    I tried And It seems like I could not create a Generic Implementation of SendMessage. It looks like I will have to Import It each time I need to use it. I got an error .
    PInvoke restriction: cannot return variants.

  8. #8
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: [RESOLVED] IntPtr vs HandleRef

    How do you mean a "generic implementation"? Not sure what you are trying to do...
    You need SendMessage declared shared, since it is an API. It is independent of your own program.

    Every API MUST return a certain type. You can not return an Object, since it can not convert the result to it.
    It is like converting a stone to a box of stones.

    Note that SendMessage always returns a Boolean or Integer indicating if the API succeeded, so no need to return other types.
    For the arguments related: both Lparam and Wparam are always integer or pointer values. In case you have to pass a StringBuilder, you actually pass a pointer to this String in memory.
    You could allocate a String in memory instead and send the pointer to that string to SendMessage.

    You could also use multiple implementations of SendMessage (like I did):
    Code:
        Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger) As Boolean
            Return SendMessage(hWnd, Msg, 0, 0)
        End Function
        Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr) As Boolean
            Return SendMessage(hWnd, Msg, wParam, 0)
        End Function
        Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Boolean
        Public Declare Function SendMessageO Lib "user32" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal Msg As UInteger, Optional ByVal wParam As Object = Nothing, Optional ByVal lParam As Object = Nothing) As Boolean

  9. #9
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: [RESOLVED] IntPtr vs HandleRef

    Quote Originally Posted by BlindSniper View Post
    What is the difference between Intptr and a normal Integer ? it seems like they both just contain numeric data ?
    I should also have mentioned that an Integer is 32-bit on all systems while an IntPtr is 32-bit on 32-bit systems and 64-bit on 64-bit systems.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  10. #10

    Thread Starter
    Fanatic Member BlindSniper's Avatar
    Join Date
    Jan 2011
    Location
    South Africa
    Posts
    865

    Re: [RESOLVED] IntPtr vs HandleRef

    Strange, I'll keep that in Mind

  11. #11
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: [RESOLVED] IntPtr vs HandleRef

    Quote Originally Posted by BlindSniper View Post
    Strange, I'll keep that in Mind
    Not really. An IntPtr is supposed to store a pointer, i.e. a memory address. Obviously memory addresses are 32-bits wide on 32-bit systems and 64-bits wide on 64-bit systems.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width