Serializing of VB-Types into ByteArrays per RtlMoveMemory is difficult, if
the type contains dynamic arrays or strings without Len-Def.
In both cases the VB-Type contains only Pointers to those members.
A solution for this problem is possible, if you work with VBs Put- and
Get-Statements against a NamedPipe.
'***Into a Form
Option Explicit
Private Declare Function CreateNamedPipe Lib "kernel32" Alias _
"CreateNamedPipeA" (ByVal lpName As String, ByVal dwOpenMode&, _
ByVal dwPipeMode As Long, ByVal nMaxInstances As Long, _
ByVal nOutBufferSize As Long, ByVal nInBufferSize As Long, _
ByVal nDefaultTimeOut As Long, lpSecurityAttributes As Any) As Long
Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, _
lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, _
lpNumberOfBytesWritten As Long, lpOverlapped As Any) As Long
Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, _
lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, _
lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long
Private Declare Function PeekNamedPipe Lib "kernel32" (ByVal hNmdPipe&, _
lpBuffer As Any, ByVal nBufferSize As Long, lpBytesRead As Long, _
lpTotalBytesAvail As Long, lpBytesLeftThisMessage As Long) As Long
Private Declare Function DisconnectNamedPipe& Lib "kernel32"(ByVal hPipe&)
Private Declare Function CloseHandle& Lib "kernel32" (ByVal hObject&)
Private Type Test
L As Long
S As String
B() As Byte
End Type
Private Sub Form_Click()
Dim T1 As Test, T2 As Test, B() As Byte
T1.L = 123
T1.S = "ABC"
ReDim T1.B(3): T1.B(1) = 1: T1.B(2) = 2: T1.B(3) = 3
Type2Bytes T1, B
Bytes2Type B, T2
Print T2.L, T2.S, T2.B(1); T2.B(2); T2.B(3)
End Sub
'results with the Count of written Bytes
Private Function Type2Bytes(T As Test, B() As Byte) As Long
Dim hPipe&, FNr&, Bytes&: Const PName$ = "\\.\pipe\Type2Bytes"
hPipe = CreateNamedPipe(PName, 3, 0, 255, -1, -1, 0, ByVal 0&)
If hPipe = -1 Then Exit Function
FNr = FreeFile
Open PName For Binary As FNr
Put FNr, , T
Close FNr
PeekNamedPipe hPipe, ByVal 0&, 0, ByVal 0&, Bytes, ByVal 0&
If Bytes > 0 Then
ReDim Preserve B(Bytes - 1)
ReadFile hPipe, B(0), Bytes, Bytes, ByVal 0&
Type2Bytes = Bytes
End If
DisconnectNamedPipe hPipe
CloseHandle hPipe
End Function
Private Function Bytes2Type(B() As Byte, T As Test) As Long
Dim hPipe&, FNr&, Bytes&: Const PName$ = "\\.\pipe\Bytes2Type"
hPipe = CreateNamedPipe(PName, 3, 0, 255, -1, -1, 0, ByVal 0&)
If hPipe = -1 Then Exit Function
FNr = FreeFile
Open PName For Binary As FNr
WriteFile hPipe, B(0), UBound(B) + 1, Bytes, ByVal 0&
If Bytes = UBound(B) + 1 Then Get FNr, , T: Bytes2Type = Loc(FNr)
Close FNr
DisconnectNamedPipe hPipe
CloseHandle hPipe
End Function
Olaf
Dick - 20 Oct 2005 04:24 GMT
Thanks very much for you help!
:)
"Schmidt" <sss@online.de> :#3C6SRR1FHA.3504@TK2MSFTNGP10.phx.gbl...
> Serializing of VB-Types into ByteArrays per RtlMoveMemory is difficult, if
> the type contains dynamic arrays or strings without Len-Def.
[quoted text clipped - 78 lines]
>
> Olaf
Karl E. Peterson - 20 Oct 2005 18:42 GMT
Hi Olaf --
> A solution for this problem is possible, if you work with VBs Put- and
> Get-Statements against a NamedPipe.
That's really pretty cool!
But it also brings UniMess into the picture, right? I mean, _if_ the UDT strings are
non-ANSI mappable (Unicode), you do run the risk of losing information, eh?
Still, for many purposes, well, I think I need to steal that! :-)
Thanks... Karl

Signature
Working Without a .NET?
http://classicvb.org/petition
> '***Into a Form
> Option Explicit
[quoted text clipped - 72 lines]
>
> Olaf
Schmidt - 21 Oct 2005 11:53 GMT
> That's really pretty cool!
You name it... ;-)
Since we have reflection-mechanisms for COM-Classes in VB (Edanmos OleLib or
per tlbinf32.dll), wich allow something like that for the public Members of
Classes even at runtime - we have no *runtime*-reflection mechanism for VBs
TypeDefs.
At least *this* thing works at Type-Level, because the Put-Statement does
something, I would call a "Macro-Like-Type-Reflection" under the hood at
CompileTime.
Put needs to know the Type it serializes explicitly, so one cannot use those
functions in a "generic way" for all possible TypeDefs.
You have to define a separate conversion-Function (Ok, you have to
CopynPaste and change only the Type in the Function-Signature) for every
single Type that you want to serialize.
Anyway - this one is not bad for internal use inside Classes regarding
serialization to - and initializing from ByteStreams.
'***Inside a Class
Private Type InternalType
PropA as String
...
End Type
Private m as InternalType
Public Property Get PropA() as String '(using 'm_'-Semantic)'
PropA = m.PropA
End Property
Public Property Let PropA(NewVal as String)
m.PropA = NewVal
End Property
'...
Public Property Get Content() as Byte()
Type2Bytes m, Content
End Property
Public Property Let Content(NewVal() as Byte)
Bytes2Type NewVal, m
End Property
Looks very clean and collects all internal Prop-Vars in one place (m).
> But it also brings UniMess into the picture, right? I mean, _if_ the UDT strings are
> non-ANSI mappable (Unicode), you do run the risk of losing information, eh?
No real problem - those StringMembers, that need to be untouched by the
implicit ANSI-conversion, have to be defined as ByteArray inside the Type.
'***enhancing our Class-example above:
Private Type InternalType
PropA as String
PropUniString() as Byte
'...
End Type
'...
Public Property Get PropUniString() as String
PropUniString= m.PropUniString
End Property
Public Property Let PropUniString(NewVal as String)
m.PropUniString = NewVal
End Property
In addition to that - for usage inside RPCs, that are implemented using a
fast, binary (maybe compressed) protocol; the implicit ANSI-Conversion is a
nice side-effect regarding the Send-/ReceiveBuffers size.
> Still, for many purposes, well, I think I need to steal that! :-)
:)
Olaf