ByRef..

  • Thread starter Thread starter VJ
  • Start date Start date
Yes. Any reason why it would be otherwise? Are you having any problems? Just
curious..

Imran.
 
It just does not work... I am trying to pass a basic string datatype ByRef
and it is not working..

VJ
 
Can you post the portion of the code where you're having the problem
including the piece of code where you're not getting what you expect? Maybe
that'll help us figure out what's going on.

Imran.
 
It just does not work... I am trying to pass a basic string datatype ByRef
and it is not working..

VJ

Strings should be passed ByVal, not ByRef. And if the dll your calling
is changing the buffer, then use System.Text.StringBuilder instead...

Heres an example...

Declare Auto Function GetUserName Lib "advapi32.dll" _
(ByVal lpBuffer System.Text.StringBuilder, _
ByRef nSize As Integer) As Boolean

Const UNLEN As Integer = 257 ' 256 + 1

....

Dim buffer As New System.Text.StringBuilder (UNLEN)
Dim nSize As Integer = buffer.Capacity

If GetUserName (buffer, nSize) Then
Return buffer.ToStrin()
Else
Throw New Win32Exception (Marshal.GetLastWin32Erro())
End If
 
Tom said:
Strings should be passed ByVal, not ByRef. And if the dll your calling
is changing the buffer, then use System.Text.StringBuilder instead...

Please why should strings be passed ByVal and not ByRef? The following
works exactly as you'd expect it to:

Public Sub Foo(ByRef s As String)
s = "Foo"
End Sub

Sub Main()
Dim hello As String = "Hello"
System.Console.WriteLine(hello)
Foo(hello)
System.Console.WriteLine(hello)
End Sub

This prints

Hello
Foo


Michi.
 
Please why should strings be passed ByVal and not ByRef? The following
works exactly as you'd expect it to:

Public Sub Foo(ByRef s As String)
s = "Foo"
End Sub

Sub Main()
Dim hello As String = "Hello"
System.Console.WriteLine(hello)
Foo(hello)
System.Console.WriteLine(hello)
End Sub

This prints

Hello
Foo


Michi.

I was assuming you were talking about interop... Calling API functions.
In, this case your dealing with pure .NET code, and that is a different
ball of wax :) In fact, in that code it won't work byval. This has a lot
to do with the concept of value types vs. reference types and the fact that
reference type variables are actually references (a special kind of
pointer) to an object, and not the actual object.

If you were talking about calling .NET objects from .NET, then yes ByRef is
the way to accomplish what your after. If you calling external API calls,
written in unmanaged Code, then things are a little different because of
the way strings are marshaled. Though, I should have said usually passed
byval, rather then byref - instead of implying that this a 100% situation,
though. In fact, in C# if I wanted to send system.string to a unmanaged
function and have it modified after the call, I would have to pass it as a
ref parameter. The reason for that is that by default reference types
(which string is one of) passed by value are marked with the InAttribute
only - so, you would not see the change made if you passed it by value.
But passing string by reference is not very efficient since there are extra
copies of the string made to make sure that the immutability of
System.String is maintained...

From MSDN:
When a System.String is passed by reference, the marshaler copies the
contents the string to a secondary buffer before making the call. It then
copies the contents of the buffer into a new string on return from the
call. This technique ensures that the immutable managed string remains
unaltered.

In VB.NET things are slightly different with System.String, because it
implements custom marshalling for the string type. For example, in VB.NET
passing the string by value will still result in the changes being visible
to the caller (to maintain some sort of backwards compatibility with
VB.CLASSIC, I would imagine) - but at the expense of even more copying,
which results in further performance degradation and less efficient memory
usage.

You can read up more on default marshalling behavior here:

http://msdn.microsoft.com/library/d...guide/html/cpcondefaultmarshalingbehavior.asp

To make a long story short... In VB.NET and C#, here are some general
rules when passing strings to unmanaged code that will generally result in
the best performance and most efficient use of memory:

1. When calling api calls that take strings, don't alias the function to
the Ansi (or A) version of the the function (this goes for strings in
structures as well). Use the Auto specifier and let the runtime figure out
the appropriate call to make. This will avoid a lot of unnecessary unicode
to ansi conversions on NT based systems.

2. If the string parameter is input only (usually prefixed with an lpsz in
the win32 api), then use system.string byval.

3. If the string is an in/out or out parameter (expected for data to be
returned in the string buffer) then don't use System.String. Use
System.Text.StringBuilder byval. By default stringbuilder byval is given
the inattribute and the outattribute and a pointer to the internal buffer
is passed directly to the unmanaged code. The caveat here is that you are
responsible to make sure that a buffer of the proper capacity is allocated
prior to the call (see, my previous example).

HTH
 

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

Back
Top