Threads and Callbacks

M

Mike

Threads and callbacks is one of the last things that needs to be
address in my .NET SDK development project.

After exploring delegate functions, I think my question pertains to
type casting unmanaged data passed back in a callback.

The native C/C++ callback prototype is:

DWORD CALLBACK DoCallback(
DWORD userdata,
const TChannelMessage *msg);

In VB, I have this:

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure TChannelMessage
Public Channel As Integer
Public SenderId As Integer
Public UserData As Short
Public DataSize As Short
<MarshalAs(UnmanagedType.ByValArray, sizeconst:=500)> _
Public Data() As Byte
End Structure

Delegate Function cbWildcatDelegate(_
ByVal userdata As Long, _
ByRef msg As TChannelMessage) as Long

Function PrepareCallback(_
ByVal cbproc As cbWildcatDelegate, _
ByVal userdata As Integer) As Boolean
' calls API to set callback address and userdata
SetupWildcatCallback(cbProc, userdata)
End Function

Function DoCallBack(_
ByVal userdata As Long, _
ByRef msg As TChannelMessage) as Long

console.Writeline("Got Milk?")
return 0
End function

The callback is done, but some there is corruption and exception which
our DLL traps.

It will worke when I changed the delegate function parameters to pointers:

Delegate Function cbWildcatDelegate(_
ByVal userdata As IntPtr, _
ByRef msg As IntPtr) as Long

Function DoCallBack(_
ByVal userdata As IntPtr, _
ByRef msg As IntPtr) as Long

console.Writeline("Got Milk?!")
return 0
End function

So the next step is to typecast the msg pointer to TChannelMessage and
also UserData. Normally, UserData is 'this' in C/C++ or I guess ME in
VB.NET?

SetupWildcatCallback(cbProc, ME) ???

In any case:

Do I use System.Runtime.InteropServices.Marshal here, if so, how?

or can I do this auto-magically with the delegate function declaration?

Also, this has been crossing my mind, is there such as thing as a PURE
non-managed type structure in .NET? I thought that is what
<StructLayout(LayoutKind.Sequential)> did for you? No?

Thanks

--
 
M

Mike

Ok, I think I am better understanding .NET, using IntPtr is a pointer
to Managed memory, so I had to use a pure 32 bit handle (integer) to
work with unmanaged memory:

This delegate signature worked:

Delegate Function cbWildcatDelegate( _
ByVal userdata As UInteger, _
ByRef msg As UInteger) As Long

Function DoCallBack( _
ByVal userdata As UInteger, _
ByRef msg As UInteger) As Long
Dim cmsg As TChannelMessage
cmsg.Channel = Marshal.ReadInt32(msg, 0)
cmsg.SenderId = Marshal.ReadInt32(msg, 4)
cmsg.UserData = Marshal.ReadInt16(msg, 8)
cmsg.DataSize = Marshal.ReadInt16(msg, 10)
Console.WriteLine("- ch: {0} sid: {1}", _
cmsg.Channel, cmsg.SenderId)
Return 0
End Function

So basically, ideally, I should create a constructor for
TChannelMessage so the above can be done easily.

Is there a *Other* more recommended way?

Thanks

--
 
A

Armin Zingler

Mike said:
The native C/C++ callback prototype is:

DWORD CALLBACK DoCallback(
DWORD userdata,
const TChannelMessage *msg);
Delegate Function cbWildcatDelegate(_
ByVal userdata As Long, _
ByRef msg As TChannelMessage) as Long

You do not know the basic data types in C/C++ and VB? This explains very
much.

Armin
Hint: Look at the size of DWORD and Long.
 
M

Mike

Armin said:
You do not know the basic data types in C/C++ and VB? This explains very
much.

I'm going to ask you to stop writing to me if you are going to insult
me. I don't think you want me as your enemy.
Armin Hint: Look at the size of DWORD and Long.

I'm compiling for 32 bit. One would expect LONG to remain 32 bit. Not
changed to 64 bit. C++ did not changed long to 64 bit.

--
 
A

Armin Zingler

Mike said:
I'm going to ask you to stop writing to me if you are going to insult me.

No insulting, just telling the truth, TROLL.
I don't think you want me as your enemy.

Right, cuz I don't wanna hurt you.
I'm compiling for 32 bit.

Yeah, that's why IntPtr = 4 bytes.
One would expect

The "One" is YOU. Don't expect; read the documentation.
LONG to remain 32 bit. Not
changed to 64 bit. C++ did not changed long to 64 bit.

Ooow, now you start crying? Bad VB!


Armin
 
T

Tom Shelton

I'm going to ask you to stop writing to me if you are going to insult
me. I don't think you want me as your enemy.


I'm compiling for 32 bit. One would expect LONG to remain 32 bit. Not
changed to 64 bit. C++ did not changed long to 64 bit.

VB.NET is not C/C++. VB.NET is based on .NET and the VB.NET datatype is
mapped to the System.Int64 datatype. Long in VB.NET is 64-bit, now and
forever.
 
M

Mike

M

Mike

Tom said:
VB.NET is not C/C++. VB.NET is based on .NET and the VB.NET datatype is
mapped to the System.Int64 datatype. Long in VB.NET is 64-bit, now and
forever.

right, now I know. As a side note, long is 32 bit in 32 bit VB6.
Surprised the same name type was changed to 64 bit in VB.NET

Thanks for your comment

--
 
T

Tom Shelton

right, now I know. As a side note, long is 32 bit in 32 bit VB6.
Surprised the same name type was changed to 64 bit in VB.NET

You shouldn't be, this is one of the major pouting points of the anti-VB.NET
bunch. VB.NET changes the size of many of the VB6 datatypes.
 
M

Mike

Tom said:
You shouldn't be, this is one of the major pouting points of the anti-VB.NET
bunch. VB.NET changes the size of many of the VB6 datatypes.

Ok understood. Please understand I am not in any way shape or form
Anti-VB.NET so I don't wish to be included in that "bunch."

This is my opinion:

It should not be strange to be surprise. In a 32 bit compilation,
using 64 bit would be the exception, and not the rule. IMO, changing
LONG to a 64 bit type in a 32-bit environment is very odd and IMO, was
not necessary and does not appear to have much value. If a developer
had a 64 bit data type need, then you use the language type available,
Int64 (signed or unsigned). Thats the case in C/C++ as well.

That said, I am sure the VB Design term had their reasons for it. If I
was privy to provide feedback back then, I would of suggested to
reconsider it for VB6 and portability sake.

Thanks for your comment.

--
 
A

Armin Zingler

Mike said:
IMO, changing
LONG to a 64 bit type in a 32-bit environment is very odd and IMO, was
not necessary and does not appear to have much value.

Only understandabe if you've never seen a file > 2 GB on a 32 bit system.
File.Length=overflow?


Armin
 
M

Mike

Armin said:
Only understandabe if you've never seen a file > 2 GB on a 32 bit
system. File.Length=overflow?

If that was the design need, then you design for it, which will
include, I might add, much more system considerations than just using
64 bit size type for lengths.

Thats not the point here.

Conceptually, Long is has been, historically and traditionally a 32
bit on a 32 bit system regardless of the language, including VB6 and
much professional training documentation even suggest to use LONG to
represent 32 bit - that is, until VB.NET and C#, which I am not
knocking. Just surprise.

Anyway, it is what it is.

Thanks for your feedback.

--
 
B

Branco

Mike wrote in another post:
The native C/C++ callback prototype is:

DWORD CALLBACK DoCallback(
DWORD userdata,
const TChannelMessage *msg);

In VB, I have this:

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure TChannelMessage
Public Channel As Integer
Public SenderId As Integer
Public UserData As Short
Public DataSize As Short
<MarshalAs(UnmanagedType.ByValArray, sizeconst:=500)> _
Public Data() As Byte
End Structure

Delegate Function cbWildcatDelegate(_
ByVal userdata As Long, _
ByRef msg As TChannelMessage) as Long

Function PrepareCallback(_
ByVal cbproc As cbWildcatDelegate, _
ByVal userdata As Integer) As Boolean
' calls API to set callback address and userdata
SetupWildcatCallback(cbProc, userdata)
End Function

Function DoCallBack(_
ByVal userdata As Long, _
ByRef msg As TChannelMessage) as Long

console.Writeline("Got Milk?")
return 0
End function

The callback is done, but some there is corruption and exception
<snip>

And then:
This delegate signature worked:

     Delegate Function cbWildcatDelegate( _
          ByVal userdata As UInteger, _
          ByRef msg As UInteger) As Long

     Function DoCallBack( _
          ByVal userdata As UInteger, _
          ByRef msg As UInteger) As Long
       Dim cmsg As TChannelMessage
       cmsg.Channel = Marshal.ReadInt32(msg, 0)
       cmsg.SenderId = Marshal.ReadInt32(msg, 4)
       cmsg.UserData = Marshal.ReadInt16(msg, 8)
       cmsg.DataSize = Marshal.ReadInt16(msg, 10)
       Console.WriteLine("- ch: {0} sid: {1}", _
                         cmsg.Channel, cmsg.SenderId)
       Return 0
     End Function

As was told by others, the probable reason you were having exceptions
and errors in your first version is because you were using Longs (64
bits) where Integers (32 bits) were expected. Changing the function
signature to IntPtr did the trick because IntPtr *is* 32 bits (notice,
however, that you're still *returning* the wrong type: Long instead of
Integer). Since the issue seems to have been explained, I'd suggest
you revert your code back to non-IntPtr usage and see if everything
works as expected.

In other words, instead of all those Marshall calls to get you struct
back, I suggest you try using the original struct declaration to see
if it flies (I guess it does):

<StructLayout(LayoutKind.Sequential, _
CharSet:=CharSet.Ansi)> _
Public Structure TChannelMessage
Public Channel As Integer
Public SenderId As Integer
Public UserData As Short
Public DataSize As Short
<MarshalAs(UnmanagedType.ByValArray, _
sizeconst:=500)> _
Public Data() As Byte
End Structure

Delegate Function cbWildcatDelegate(_
ByVal userdata As Integer, _
ByRef msg As TChannelMessage) As Integer

Function DoCallBack( _
ByVal userdata As Integer, _
ByRef msg As TChannelMessage) As Integer
Console.WriteLine("- ch: {0} sid: {1}", _
msg.Channel, msg.SenderId)
Return 0
End Function

Best regards,

Branco.
 
M

Mike

Branco said:
Mike wrote in another post:
I'd suggest
you revert your code back to non-IntPtr usage and see if everything
works as expected.

It did! Thanks.


Just a side point and IMV, good for people to keep in mind. For 32 bit
compiles, Long is only 64 bit in .NET. long is 32 bit everywhere else
for 32 bit compiles. For extensive mixed language developers it is an
important point to keep in mind.

For the record, this MSDN .NET Framework page

http://msdn.microsoft.com/en-us/library/0wf2yk2k(VS.80).aspx

has long as System.Int32 for C++.

It threw me off course thinking VB.NET followed it and never in my
life would I had consider VB.NET LONG would not be the same. I hope
others can understand that it was not completely my fault. :)

But I over thought the problem and did more than I needed too, looking
into serialization methods, including spending the day looking at our
Java SDK that does serialization and was very happily surprise to see
that it compiled 100% as a .NET DLL.

This serialization approach is no longer needed. I greatly appreciate
your technical follow up.

I don't see any other surprises in the VB.NET type sizes:

http://msdn.microsoft.com/en-us/library/47zceaw7.aspx

LONG appears to be the exception.

Thanks again Branco.

--
 
T

Tom Shelton

Mike wrote in another post:

<snip>

And then:


As was told by others, the probable reason you were having exceptions
and errors in your first version is because you were using Longs (64
bits) where Integers (32 bits) were expected. Changing the function
signature to IntPtr did the trick because IntPtr *is* 32 bits (notice,

Just a note - IntPtr is 32-bit on 32-bit systems. It's 64-bit on 64-bit
systems....
 
T

Tom Shelton

Mike wrote in another post:

<snip>

And then:


As was told by others, the probable reason you were having exceptions
and errors in your first version is because you were using Longs (64
bits) where Integers (32 bits) were expected. Changing the function
signature to IntPtr did the trick because IntPtr *is* 32 bits (notice,

Just a note - IntPtr is 32-bit on 32-bit systems. It's 64-bit on 64-bit
systems....
 
B

Branco

Tom Shelton wrote:
Just a note - IntPtr is 32-bit on 32-bit systems.  It's 64-bit on 64-bit
systems....
<snip>

Thanks for the heads up. It's obvious (once you know it =))

Regards,

Branco.
 
B

Branco

Tom Shelton wrote:
Just a note - IntPtr is 32-bit on 32-bit systems.  It's 64-bit on 64-bit
systems....
<snip>

Thanks for the heads up. It's obvious (once you know it =))

Regards,

Branco.
 

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