|
-
Dec 3rd, 2005, 02:00 AM
#1
Thread Starter
Frenzied Member
confused about GetModuleFileName()
ok, i'm calling GetMOduleFileName from VB.NET. So i declared:
VB Code:
Public Declare Function GetModuleFileName Lib "kernel32" Alias "GetModuleFileNameA" (ByVal hModule As Integer, ByVal lpFileName As String, ByVal nSize As Integer) As Integer
notice that lpFileName is passed "ByVal". Now here's the thing, lpFileName is a pointer to the buffer that will receive the null terminated string. So shouldn't it be "ByRef"? Because if it's "ByVal", the api function GetModuleFileName will be getting the value instead, right? It should be passing ByRef, yet it only works if its ByVal.
-
Dec 7th, 2005, 09:04 AM
#2
Re: confused about GetModuleFileName()
A quick quote from MSDN will clear your confusion, indeed:
ByVal
A way of passing the value of an argument to a procedure instead of passing the address. This allows the procedure to access a copy of the variable. As a result, the variable's actual value can't be changed by the procedure to which it is passed.
-
Dec 7th, 2005, 09:39 AM
#3
Re: confused about GetModuleFileName()
Sorry benmartin101 for posting in your thread.
I had subscribed the thread form the day you posted. 
Rhino, I'm still confused. 
As the MSDN quote says (and we all know) when passing ByVal, the "variable's actual value can't be changed by the procedure to which it is passed".
That means, as GetModuleFileName is getting lpFileName by value, it can't change the original string in our calling module.
But, in fact, it fills the string with new value in our calling module.
VB Code:
Option Explicit
Private Declare Function GetModuleFileName Lib "kernel32" _
Alias "GetModuleFileNameA" _
(ByVal hModule As Long, _
ByVal lpFileName As String, _
ByVal nSize As Long) As Long
Private Declare Function GetWindowWord Lib "user32" _
(ByVal hwnd As Long, _
ByVal nIndex As Long) As Integer
Const GWW_HINSTANCE = (-6)
Private Sub Form_Load()
Dim ModuleName As String * 128, FileName As String, hInst As Long
'create a buffer
ModuleName = String(128, Chr$(0))
'get the hInstance application:
hInst = GetWindowWord(Me.hwnd, GWW_HINSTANCE)
'--------------------------------
MsgBox "ModuleName [b]BEFORE[/b] calling GetModuleFileName : " & ModuleName
'--------------------------------
Call GetModuleFileName(hInst, ModuleName, Len(ModuleName))
'--------------------------------
MsgBox "ModuleName [b]AFTER[/b] calling GetModuleFileName : " & ModuleName
'--------------------------------
End Sub
Last edited by iPrank; Dec 7th, 2005 at 09:43 AM.
-
Dec 7th, 2005, 09:39 AM
#4
Re: confused about GetModuleFileName()
In .NET Strings are immutable, so you would pass a StringBuilder ByRef and then call its .ToString() method to retrieve the string contents.
VB Code:
Imports System.Runtime.InteropServices
<DllImport("kernel32", EntryPoint:="GetModuleFileNameW")> Private Shared Function GetModuleFileName ( _
ByVal hModule As Integer, _
<MarshalAs(UnmanagedType.LPWStr)> ByRef lpFilename As StringBuilder, _
ByVal nSize As Integer _
) As Integer
-
Dec 7th, 2005, 09:44 AM
#5
Re: confused about GetModuleFileName()
@ iPrank - this is VB.NET, it's different. Strings in VB6 are not classes, they are just pointers to BSTRs which are string buffers. The buffer content CAN be changed. In VB.NET the String class is immutable, that means the buffer content CANNOT be changed.
Also, since we are using ByVal with a string, a futher caveat applies. In VB6 when you pass a string ByVal to an API function, VB makes a temporary ANSI buffer from your original Unicode string, and passes a pointer to that buffer to the API function. When the function returns the buffer is converted back to Unicode into your original string.
If you use the -W Unicode API functions instead, you declare it ByVal ... As Long, and use StrPtr(stringname) to pass a pointer to the Unicode buffer directly. That saves all the conversion stuff.
However, if you use ByVal to pass a string WITHIN your VB application, a Unicode copy is made. Therein lies the difference.
-
Dec 7th, 2005, 09:46 AM
#6
Re: confused about GetModuleFileName()
 Originally Posted by benmartin101
It should be passing ByRef, yet it only works if its ByVal.
I missed this part. In that case it is because you are calling the ANSI version of the function, so the same Unicode->ANSI->Unicode marshalling takes place as in VB6, which is why it works. If you use DllImport it allows you to specify Charset:=Charset.Unicode which means no Unicode->ANSI conversion will take place. Alternatively, if you must use the Declare syntax, you can use the Unicode keyword on it (Private Declare Unicode Function).
-
Dec 7th, 2005, 09:52 AM
#7
Re: confused about GetModuleFileName()
-
Dec 7th, 2005, 02:03 PM
#8
Thread Starter
Frenzied Member
Re: confused about GetModuleFileName()
still a bit confused. Tell me, in this code:
VB Code:
Public Declare Function GetModuleFileName Lib "kernel32" Alias "GetModuleFileNameA" (ByVal hModule As Integer, ByVal lpFileName As String, ByVal nSize As Integer) As Integer
is lpFileName's address or value being send to the function? Now, the way I see it, the address is being passed, even though its ByVal.
And in this code:
VB Code:
Public Function Func1(ByVal x As String)
x = "Hello"
end function
is x's address or value being passed? To me, x is being passed by value.
-
Dec 7th, 2005, 03:32 PM
#9
Thread Starter
Frenzied Member
Re: confused about GetModuleFileName()
I just tried this out in c#:
[DllImport("kernel32")]
extern static int GetModuleFileName(int hMod, String lpFilename, int size);
and it doesn't work, but if I change String to StringBuilder, then it works, how come?
-
Dec 7th, 2005, 11:56 PM
#10
Re: confused about GetModuleFileName()
I've explained why it passes the address even with ByVal.
when you pass a string ByVal to an API function, VB makes a temporary ANSI buffer from your original Unicode string, and passes a pointer to that buffer to the API function. When the function returns the buffer is converted back to Unicode into your original string.
and also about StringBuilder
In VB.NET the String class is immutable, that means the buffer content CANNOT be changed.
which is why you use StringBuilder instead, which is NOT immutable.
-
Dec 8th, 2005, 01:11 PM
#11
Thread Starter
Frenzied Member
Re: confused about GetModuleFileName()
oh ok, i got it now. Thanks.
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
|