|
-
Apr 3rd, 2011, 04:49 AM
#1
Thread Starter
Fanatic Member
[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 ?
-
Apr 3rd, 2011, 05:07 AM
#2
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.
-
Apr 3rd, 2011, 05:50 AM
#3
Fanatic Member
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
-
Apr 3rd, 2011, 06:49 AM
#4
Thread Starter
Fanatic Member
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.
-
Apr 3rd, 2011, 06:54 AM
#5
Fanatic Member
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:
Public Class WM Public Enum SC 'System Commands CLOSE = &HF060 CONTEXTHELP = &HF180 CDEFAULT = &HF160 HOTKEY = &HF150 HSCROLL = &HF080 ISSECURE = &H1 KEYMENU = &HF100 MAXIMIZE = &HF030 MINIMIZE = &HF020 MONITORPOWER = &HF170 MouseMenu = &HF090 MOVE = &HF010 NEXTWINDOW = &HF040 PREVWINDOW = &HF050 RESTORE = &HF120 SCREENSAVE = &HF140 Size = &HF000 TASKLIST = &HF130 VSCROLL = &HF070 End Enum Public Enum msg As UInteger USER = &H400& ACTIVATE = &H6 ACTIVATEAPP = &H1C ASKCBFORMATNAME = &H30C CANCELJOURNAL = &H4B CANCELMODE = &H1F CHANGECBCHAIN = &H30D Chr = &H102 CHARTOITEM = &H2F CHILDACTIVATE = &H22 CHOOSEFONT_GETLOGFONT = (USER + 1) CHOOSEFONT_SETFLAGS = (USER + 102) CHOOSEFONT_SETLOGFONT = (USER + 101) CLEAR = &H303 CLOSE = &H10 Command = &H111 COMMNOTIFY = &H44 ' no longer suported COMPACTING = &H41 COMPAREITEM = &H39 CONVERTREQUESTEX = &H108 Copy = &H301 COPYDATA = &H4A CREATE = &H1 CTLCOLORBTN = &H135 CTLCOLORDLG = &H136 CTLCOLOREDIT = &H133 CTLCOLORLISTBOX = &H134 CTLCOLORMSGBOX = &H132 CTLCOLORSCROLLBAR = &H137 CTLCOLORSTATIC = &H138 CUT = &H300 DDE_FIRST = &H3E0 DDE_ACK = (DDE_FIRST + 4) DDE_ADVISE = (DDE_FIRST + 2) DDE_DATA = (DDE_FIRST + 5) DDE_EXECUTE = (DDE_FIRST + 8) DDE_INITIATE = (DDE_FIRST) DDE_LAST = (DDE_FIRST + 8) DDE_POKE = (DDE_FIRST + 7) DDE_REQUEST = (DDE_FIRST + 6) DDE_TERMINATE = (DDE_FIRST + 1) DDE_UNADVISE = (DDE_FIRST + 3) DEADCHAR = &H103 DELETEITEM = &H2D DESTROY = &H2 DESTROYCLIPBOARD = &H307 DEVMODECHANGE = &H1B DRAWCLIPBOARD = &H308 DRAWITEM = &H2B DROPFILES = &H233 ENABLE = &HA ENDSESSION = &H16 ENTERIDLE = &H121 ENTERMENULOOP = &H211 ERASEBKGND = &H14 EXITMENULOOP = &H212 FONTCHANGE = &H1D GETFONT = &H31 GETDLGCODE = &H87 GETHOTKEY = &H33 GETMINMAXINFO = &H24 GETTEXT = &HD GETTEXTLENGTH = &HE HOTKEY = &H312 HSCROLL = &H114 HSCROLLCLIPBOARD = &H30E ICONERASEBKGND = &H27 IME_CHAR = &H286 IME_COMPOSITION = &H10F IME_COMPOSITIONFULL = &H284 IME_CONTROL = &H283 IME_ENDCOMPOSITION = &H10E IME_KEYDOWN = &H290 IME_KEYLAST = &H10F IME_KEYUP = &H291 IME_NOTIFY = &H282 IME_SELECT = &H285 IME_SETCONTEXT = &H281 IME_STARTCOMPOSITION = &H10D INITDIALOG = &H110 INITMENU = &H116 INITMENUPOPUP = &H117 KEYDOWN = &H100 KEYFIRST = &H100 KEYLAST = &H108 KEYUP = &H101 KILLFOCUS = &H8 LBUTTONDBLCLK = &H203 LBUTTONDOWN = &H201 LBUTTONUP = &H202 MBUTTONDBLCLK = &H209 MBUTTONDOWN = &H207 MBUTTONUP = &H208 MDIACTIVATE = &H222 MDICASCADE = &H227 MDICREATE = &H220 MDIDESTROY = &H221 MDIGETACTIVE = &H229 MDIICONARRANGE = &H228 MDIMAXIMIZE = &H225 MDINEXT = &H224 MDIREFRESHMENU = &H234 MDIRESTORE = &H223 MDISETMENU = &H230 MDITILE = &H226 MEASUREITEM = &H2C MENUCHAR = &H120 MENUSELECT = &H11F MOUSEACTIVATE = &H21 MOUSEFIRST = &H200 MOUSELAST = &H209 MOUSEMOVE = &H200 MOVE = &H3 NCACTIVATE = &H86 NCCALCSIZE = &H83 NCCREATE = &H81 NCDESTROY = &H82 NCHITTEST = &H84 NCLBUTTONDBLCLK = &HA3 NCLBUTTONDOWN = &HA1 NCLBUTTONUP = &HA2 NCMBUTTONDBLCLK = &HA9 NCMBUTTONDOWN = &HA7 NCMBUTTONUP = &HA8 NCMOUSEMOVE = &HA0 NCPAINT = &H85 NCRBUTTONDBLCLK = &HA6 NCRBUTTONDOWN = &HA4 NCRBUTTONUP = &HA5 NEXTDLGCTL = &H28 NULL = &H0 PAINT = &HF PAINTCLIPBOARD = &H309 PAINTICON = &H26 PALETTECHANGED = &H311 PALETTEISCHANGING = &H310 PARENTNOTIFY = &H210 PASTE = &H302 PENWINFIRST = &H380 PENWINLAST = &H38F POWER = &H48 Print = &H317 PSD_ENVSTAMPRECT = (USER + 5) PSD_FULLPAGERECT = (USER + 1) PSD_GREEKTEXTRECT = (USER + 4) PSD_MARGINRECT = (USER + 3) PSD_MINMARGINRECT = (USER + 2) PSD_PAGESETUPDLG = (USER) PSD_YAFULLPAGERECT = (USER + 6) QUERYDRAGICON = &H37 QUERYENDSESSION = &H11 QUERYNEWPALETTE = &H30F QUERYOPEN = &H13 QUEUESYNC = &H23 QUIT = &H12 RBUTTONDBLCLK = &H206 RBUTTONDOWN = &H204 RBUTTONUP = &H205 RENDERALLFORMATS = &H306 RENDERFORMAT = &H305 SETCURSOR = &H20 SETFOCUS = &H7 SETFONT = &H30 SETHOTKEY = &H32 SETREDRAW = &HB SETTEXT = &HC Size = &H5 SIZECLIPBOARD = &H30B SPOOLERSTATUS = &H2A SYSCHAR = &H106 SYSCOLORCHANGE = &H15 SYSCOMMAND = &H112 SYSDEADCHAR = &H107 SYSKEYDOWN = &H104 SYSKEYUP = &H105 SHOWWINDOW = &H18 Timer = &H113 TIMECHANGE = &H1E UNDO = &H304 VKEYTOITEM = &H2E VSCROLL = &H115 VSCROLLCLIPBOARD = &H30A WINDOWPOSCHANGED = &H47 WINDOWPOSCHANGING = &H46 WININICHANGE = &H1A End Enum 'Window Messages Public Shared Function GETTEXTLENGTH(ByVal hwnd As IntPtr) As Integer Return DefWindowProc(hwnd, 14, 0, 0) + 1 End Function Public Shared Property TEXT(ByVal hwnd As IntPtr) As String Get Dim length As Integer = GETTEXTLENGTH(hwnd) Dim Handle As IntPtr = Runtime.InteropServices.Marshal.AllocHGlobal(length) DefWindowProc(hwnd, 13, length, Handle) Return Runtime.InteropServices.Marshal.PtrToStringAnsi(Handle) End Get Set(ByVal value As String) DefWindowProc(hwnd, &HC, IntPtr.Zero, Runtime.InteropServices.Marshal.StringToHGlobalAnsi(value)) End Set End Property Public Shared Property FONT(ByVal hwnd As IntPtr) As System.Drawing.Font Get Return System.Drawing.Font.FromHfont(SendMessage(hwnd, msg.GETFONT)) End Get Set(ByVal value As System.Drawing.Font) SendMessage(hwnd, msg.SETFONT, value.ToHfont, True) End Set End Property Public Shared Function CLOSE(ByVal hwnd As IntPtr) As Integer Return DefWindowProc(hwnd, msg.CLOSE, 0, 0) End Function Public Shared Function DESTROY(ByVal hwnd As IntPtr) As Integer Return DefWindowProc(hwnd, msg.DESTROY, 0, 0) End Function Public Shared Function CLEAR(ByVal hwnd As IntPtr) As Integer Return DefWindowProc(hwnd, msg.CLEAR, 0, 0) End Function Public Shared Function UNDO(ByVal hwnd As IntPtr) As Integer Return DefWindowProc(hwnd, msg.UNDO, 0, 0) End Function Public Shared Function SYSCOMMAND(ByVal hwnd As IntPtr, ByVal command As SC, Optional ByVal lparam As Integer = 0) As Boolean Return DefWindowProc(hwnd, WM.msg.SYSCOMMAND, command, lparam) End Function Public Shared Function SYSCOMMAND(ByVal hwnd As IntPtr, ByVal command As SC, ByVal x As Short, ByVal y As Short) As Boolean Return DefWindowProc(hwnd, WM.msg.SYSCOMMAND, command, New DWORD(x, y).Integer1) End Function 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.
Last edited by bergerkiller; Apr 3rd, 2011 at 07:04 AM.
-
Apr 3rd, 2011, 07:08 AM
#6
Thread Starter
Fanatic Member
Re: IntPtr vs HandleRef
Cool, Thanks I'll Post My SendMessage Implimentation When i'm Done.
-
Apr 3rd, 2011, 07:29 AM
#7
Thread Starter
Fanatic Member
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.
-
Apr 3rd, 2011, 09:32 AM
#8
Fanatic Member
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
Last edited by bergerkiller; Apr 3rd, 2011 at 09:45 AM.
-
Apr 4th, 2011, 09:39 AM
#9
Re: [RESOLVED] IntPtr vs HandleRef
 Originally Posted by BlindSniper
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.
-
Apr 4th, 2011, 09:45 AM
#10
Thread Starter
Fanatic Member
Re: [RESOLVED] IntPtr vs HandleRef
Strange, I'll keep that in Mind
-
Apr 4th, 2011, 09:51 AM
#11
Re: [RESOLVED] IntPtr vs HandleRef
 Originally Posted by BlindSniper
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.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|