Does String mashal default to UnmanagedType.LPTStr

D

**Developer**

Been reading some of the Marshal doc and am a little confused.

Anyway, I've been using the following and it works OK.

Public Declare Auto Function SHGetFolderPath Lib "shell32.dll" (ByVal hWnd
As Integer, _

ByVal nFolder As Integer, ByVal nToken As Integer, _

ByVal dwFlags As Integer, _

<MarshalAs(UnmanagedType.LPTStr)> ByVal lpszPath As String) As Boolean



Tried this because I saw some place (not in the doc) that
UnmanagedType.LPTStr was the default for String. This works too.

Public Declare Auto Function SHGetFolderPath Lib "shell32.dll" (ByVal hWnd
As Integer, _

ByVal nFolder As Integer, ByVal nToken As Integer, _

ByVal dwFlags As Integer, _

ByVal lpszPath As String) As Boolean

Is that correct. I.e., in VB, String mashal defaults to
UnmanagedType.LPTStr so UnmanagedType.LPTStr need not be included??



This is how it's used:

Dim lPath As String = Space(260)

If Library.Shell.SHGetFolderPath(0, k, 0, 0, lPath) = 0 Then

lPath = lPath.Trim

lPath = lPath.Substring(0, lPath.Length - 1)

GetSpecialPath = lPath

End If



Finally, is that the correct way to do it or should I use StringBuilder.

If it's not the correct way, why not? It appears to work OK.



Thanks in advance
 
T

Tom Shelton

Been reading some of the Marshal doc and am a little confused.

Anyway, I've been using the following and it works OK.

Finally, is that the correct way to do it or should I use StringBuilder.

For buffers populated by the called function, you really should use
StringBuilder.
If it's not the correct way, why not? It appears to work OK.

Here are a couple of reasons:

1) Strings in .NET are immutable. By passing a type of string to the
marshaller, you are causing it to do extra work. Basically, the
marshaller, must copy data to a buffer, call the function, and then copy
the buffer back to your string. When you use a StringBuilder, it just
passes the buffer. You probably won't notice the performance hit unless
your in a long loop or something... But, still why cause the marshaller
to work harder then it needs to :)

2) This technique of using a string as a modifiable buffer will not work
in other languages - for example C#. Not that you probably care, but if
you have to do work in that language suddenly and try to declare the
function the way you did, you might spend needless time debuggin why it
didn't work.

Of course, I have to ask... Do you really need this function? Have
yous seen System.Environment.GetFolderPath?
 
D

**Developer**

Of course, I have to ask... Do you really need this function? Have
yous seen System.Environment.GetFolderPath?


If I didn't use that function I would not have needed to ask and would not
have the learned what you just told me. I like to try things since that
often bring to the front good things to know.

Thanks a lot
 
D

**Developer**

Using StringBuilder do I need to set the Capacity or length or fill it with
anything before the call?


Thanks again
 
D

**Developer**

This is what I've done and it appears to work:

Dim lPath As New System.Text.StringBuilder(Library.Kernel.MAX_PATH)

'Dim lPath As String = Space(260)

If Library.Shell.SHGetFolderPath(0, k, 0, 0, lPath) = 0 Then
 
J

Jay B. Harlow [MVP - Outlook]

**Developer**
In addition to the other comments, the default for VB.NET is
UnmanagedType.VBByRefStr, which allows the string itself (which is
immutable) to be modified by the API call. This allows consistency with VB6
and "simplifies" things.

However as Tom suggests, I normally use StringBuilder, as StringBuilder is
mutable, while String is immutable. Also
<MarshalAs(UnmanagedType.VBByRefStr)> can only be used with "InOut"
parameters, if you start adding InAttribute or OutAttribute to the declare
statement parameters you need to give a MarshalAs with the 'regular' string
types <MarshalAs(UnmanagedType.LPTStr)> for example, other wise you get an
exception from the Marshaller.

If you are not concerned with the InAttribute or OutAttribute then the
"default" behavior of VBByRefStr is reasonable for the Declare statement. As
it mimics what VB6 would do.

I normally include InAttribute & OutAttribute on my Declare statements...

Hope this helps
Jay


| Been reading some of the Marshal doc and am a little confused.
|
| Anyway, I've been using the following and it works OK.
|
| Public Declare Auto Function SHGetFolderPath Lib "shell32.dll" (ByVal hWnd
| As Integer, _
|
| ByVal nFolder As Integer, ByVal nToken As Integer, _
|
| ByVal dwFlags As Integer, _
|
| <MarshalAs(UnmanagedType.LPTStr)> ByVal lpszPath As String) As Boolean
|
|
|
| Tried this because I saw some place (not in the doc) that
| UnmanagedType.LPTStr was the default for String. This works too.
|
| Public Declare Auto Function SHGetFolderPath Lib "shell32.dll" (ByVal hWnd
| As Integer, _
|
| ByVal nFolder As Integer, ByVal nToken As Integer, _
|
| ByVal dwFlags As Integer, _
|
| ByVal lpszPath As String) As Boolean
|
| Is that correct. I.e., in VB, String mashal defaults to
| UnmanagedType.LPTStr so UnmanagedType.LPTStr need not be included??
|
|
|
| This is how it's used:
|
| Dim lPath As String = Space(260)
|
| If Library.Shell.SHGetFolderPath(0, k, 0, 0, lPath) = 0 Then
|
| lPath = lPath.Trim
|
| lPath = lPath.Substring(0, lPath.Length - 1)
|
| GetSpecialPath = lPath
|
| End If
|
|
|
| Finally, is that the correct way to do it or should I use StringBuilder.
|
| If it's not the correct way, why not? It appears to work OK.
|
|
|
| Thanks in advance
|
|
|
|
|
|
 
D

**Developer**

<MarshalAs(UnmanagedType.VBByRefStr)> can only be used with "InOut"
parameters, if you start adding InAttribute or OutAttribute to the declare
statement parameters you need to give a MarshalAs with the 'regular'
string
types <MarshalAs(UnmanagedType.LPTStr)> for example, other wise you get an
exception from the Marshaller.
Can't follow this. Seems to say VBByRefStr requires InOut.
Then says In or Out requires LPTStr or something similar.

What am I reading wrong?



Thanks
 
J

Jay B. Harlow [MVP - Outlook]

**Developer**,
| Can't follow this. Seems to say VBByRefStr requires InOut.

That is exactly what I stated: VBByRefStr requires (can only be used for)
InOut parameters. InOut parameters are parameters that do not have an
InAttribute or an OutAttribute attached to them.

InOut parameters are parameters that are marshaled to the unmanaged world &
then marshaled back to the .NET world.

In parameters only need to be marshaled to the unmanaged world (they are
values that go into the API, are not returned.). They have the
System.Runtime.InteropServices.InAttribute attached to them.

http://msdn.microsoft.com/library/d...ntimeInteropServicesInAttributeClassTopic.asp

Out parameters only need to be marshaled to the .NET world (they are values
that are returned from an API). They have the
System.Runtime.InteropServices.OutAttribute attached to them.

http://msdn.microsoft.com/library/d...timeInteropServicesOutAttributeClassTopic.asp

If you read the Win32 API itself, the description of the parameters indicate
if they are In, Out, or InOut.

http://msdn.microsoft.com/library/d...shell/reference/functions/shgetfolderpath.asp


| Then says In or Out requires LPTStr or something similar.
Correct, as VB will attempt to put VBByRefStr if you don't include LPTStr.
VBByRefStr with InAttribute or OutAttribute is incompatible.

InAttribute & OutAttribute allow you to "optimize" the API call as they
allow you to indicate that a parameter only needs to be marshaled in a
single direction, allowing the API itself to be quicker.

In the case of SHGetFolderPath , the lpszPath is used to return a String, it
should (*should*) have the OutAttribute on it as it is a return value.
OutAttribute means you need StringBuilder as String with LPTStr is
immutable.

For an example of declaring the API see:

http://www.pinvoke.net/default.aspx/shell32/SHGetFolderPath.html

Using the Declare syntax:

Private Declare Auto Function SHGetFolderPath Lib "shell32.dll" ( _
ByVal hwndOwner As IntPtr, _
ByVal nFolder As Int32, _
ByVal hToken As IntPtr, _
ByVal dwFlags As Int32, _
<Out()> ByVal pszPath As StringBuilder _
) As Int32

InAttribute is implicit on ByVal value types. String & StringBuiler are
reference types so you need to state if they are In only or Out only,
otherwise InOut is assumed.

I find both the www.pinvoke.net web site & Adam Nathan's book ".NET and
COM - The Complete Interoperability Guide" from SAMS press to be invaluable
when using Declare statements & P/Invoke.

Hope this helps
Jay




Hope this helps
Jay


|
| > <MarshalAs(UnmanagedType.VBByRefStr)> can only be used with "InOut"
| > parameters, if you start adding InAttribute or OutAttribute to the
declare
| > statement parameters you need to give a MarshalAs with the 'regular'
| > string
| > types <MarshalAs(UnmanagedType.LPTStr)> for example, other wise you get
an
| > exception from the Marshaller.
| >
| Can't follow this. Seems to say VBByRefStr requires InOut.
| Then says In or Out requires LPTStr or something similar.
|
| What am I reading wrong?
|
|
|
| Thanks
|
|
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top