msvisual.com Forum Index
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister   ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Aliasing a UDT
Goto page 1, 2  Next
 
Post new topic   Reply to topic    msvisual.com Forum Index -> VB WinAPI
Author Message
Jeremiah D. Seitz



Joined: 09 Jan 2008
Posts: 26

PostPosted: Wed Feb 06, 2008 12:26 am    Post subject: Aliasing a UDT Reply with quote

Hiya,

I'm sure many of us have seen the vbAccelerator code for DIB
sections. In the code, Steve aliases an array variable to point to
existing data stored elsewhere.

The basic idea, for those who don't know, is that you can
declare an empty array variable, perform a little API-fu, and access
the data stored in another array, while only copying 4 bytes.

Getting to the point, is there a way of doing the same thing
with a UDT? Even better, a UDT array?

Unless I'm missing something, there is no intrinsic way to
pass a UDT array ByRef. I end up with a copy of the array instead.
What I'd really like is to pass a pointer to another process, and have
that process be able to access the original UDT array.

Thanks in advance,

J.
Jeremiah D. Seitz
Omega Techware
http://www.omegatechware.net

Archived from group: microsoft>public>vb>winapi
Back to top
View user's profile Send private message
Ralph



Joined: 04 Oct 2007
Posts: 4148

PostPosted: Wed Feb 06, 2008 12:00 am    Post subject: Re: Aliasing a UDT Reply with quote

"Jeremiah D. Seitz" wrote in message@4ax.com...
> Hiya,
>
> I'm sure many of us have seen the vbAccelerator code for DIB
> sections. In the code, Steve aliases an array variable to point to
> existing data stored elsewhere.
>
> The basic idea, for those who don't know, is that you can
> declare an empty array variable, perform a little API-fu, and access
> the data stored in another array, while only copying 4 bytes.
>
> Getting to the point, is there a way of doing the same thing
> with a UDT? Even better, a UDT array?
>
> Unless I'm missing something, there is no intrinsic way to
> pass a UDT array ByRef. I end up with a copy of the array instead.
> What I'd really like is to pass a pointer to another process, and have
> that process be able to access the original UDT array.
>
> Thanks in advance,
>

Convert your UDT to a Class.
For a "UDT Array" pass a Typed Collection Class.

-ralph
Back to top
View user's profile Send private message
Jeremiah D. Seitz



Joined: 09 Jan 2008
Posts: 26

PostPosted: Wed Feb 06, 2008 1:53 am    Post subject: Re: Aliasing a UDT Reply with quote

On Tue, 5 Feb 2008 19:00:30 -0600, "Ralph"
wrote:

>Convert your UDT to a Class.
>For a "UDT Array" pass a Typed Collection Class.

Thanks for responding, Ralph. Unfortunately, performance is an issue,
and the VB collection object just doesn't cut it. There is a
logarithmic increase in the time required to clear a collection, which
I consider unacceptable for my purposes. In one notable case, the
number of items exceeded 300,000 - way too many for a collection. The
array barely handled it.

I'm sure the aliasing concept can be applied to UDTs; I'm just not
privy to the *how* of it.

>-ralph

Thanks,

J
Jeremiah D. Seitz
Omega Techware
http://www.omegatechware.net
Back to top
View user's profile Send private message
Jim Mack



Joined: 04 Oct 2007
Posts: 735

PostPosted: Wed Feb 06, 2008 3:00 am    Post subject: Re: Aliasing a UDT Reply with quote

Jeremiah D. Seitz wrote:
> Hiya,
>
> I'm sure many of us have seen the vbAccelerator code for DIB
> sections. In the code, Steve aliases an array variable to point to
> existing data stored elsewhere.
>
> The basic idea, for those who don't know, is that you can
> declare an empty array variable, perform a little API-fu, and access
> the data stored in another array, while only copying 4 bytes.
>
> Getting to the point, is there a way of doing the same thing
> with a UDT? Even better, a UDT array?
>
> Unless I'm missing something, there is no intrinsic way to
> pass a UDT array ByRef. I end up with a copy of the array instead.
> What I'd really like is to pass a pointer to another process, and
> have that process be able to access the original UDT array.
>

If you're literally talking about a separate process, then no. As you
know, separate processes have separate memory spaces: anything shared
between them must be marshalled across those spaces. And for a UDT
that involves a deep copy. If the UDT contains objects, you're getting
way complicated.

So, do you really mean separate processes? Because if you drop that
requirement, what you want may be do-able. How easy it is depends on
what the UDT contains.

--
Jim
Back to top
View user's profile Send private message
Ralph



Joined: 04 Oct 2007
Posts: 4148

PostPosted: Wed Feb 06, 2008 3:30 am    Post subject: Re: Aliasing a UDT Reply with quote

"Jeremiah D. Seitz" wrote in message@4ax.com...
> On Tue, 5 Feb 2008 19:00:30 -0600, "Ralph"
> wrote:
>
> >Convert your UDT to a Class.
> >For a "UDT Array" pass a Typed Collection Class.
>
> Thanks for responding, Ralph. Unfortunately, performance is an issue,
> and the VB collection object just doesn't cut it. There is a
> logarithmic increase in the time required to clear a collection, which
> I consider unacceptable for my purposes. In one notable case, the
> number of items exceeded 300,000 - way too many for a collection. The
> array barely handled it.
>
> I'm sure the aliasing concept can be applied to UDTs; I'm just not
> privy to the *how* of it.
>
> >-ralph
>
> Thanks,
>

As Jim noted if this is something for a different "process" (program) then
we are likely talking about else, but ... Passing a UDT as an Object will
full-fill your object. (pun intended ) in either case.

As for the problems with a VB Collection, you are correct. VB Collections
are not known as being high performers. However, there are alternatives to
the VB Collection which will do better. I'll fish about and see if I can't
find a few URLs.

However, you can still benefit from a "Collection Class". If you aren't
familiar with them just load up the VB Class Builder, create a simple class,
and then create a Collection Class to wrap it. In the generated code you
will see that it wraps a VB Collection. You do NOT have to use a VB
Collection. You could substitute any kind of bag you wish. Either one the
replacements or your original array.

From that point you can do practically anything to mangle its presentation
for a client. You might use the default Interface to manage the 'wrapper'
and then create an additional Interface to supply a simple 'UDT' for the
client.

Don't be alarmed at what might appear to be a 'large' object - at runtime
only the Interfaces (vtables) and the Data is all that matters.

Another thing you can try is to declare your Type in a type library. This is
a way of getting around VB's restriction against Public UDTs. The problem is
due to VB's way of defining 'public' values and essentially can't be alias'd
in VB. Make sure the type lib is within scope of both the client and service
and this will assist in removing some issues in passing UDTs, but you still
have a problem with an array.

hth
-ralph
Back to top
View user's profile Send private message
Schmidt



Joined: 04 Oct 2007
Posts: 806

PostPosted: Wed Feb 06, 2008 6:17 pm    Post subject: Re: Aliasing a UDT Reply with quote

"Jeremiah D. Seitz" schrieb im Newsbeitrag@4ax.com...

> Unless I'm missing something, there is no intrinsic way to
> pass a UDT array ByRef. I end up with a copy of the
> array instead.
> What I'd really like is to pass a pointer to another process,
> and have that process be able to access the original UDT array.
As long as you have control over (VB-Source for) both
Processes, then there shouldn't be a problem.

Can you describe your current scenario a bit more
detailed?

Olaf
Back to top
View user's profile Send private message
Ralph



Joined: 04 Oct 2007
Posts: 4148

PostPosted: Wed Feb 06, 2008 1:58 pm    Post subject: Re: Aliasing a UDT Reply with quote

"Jeremiah D. Seitz" wrote in message@4ax.com...
> On Tue, 5 Feb 2008 19:00:30 -0600, "Ralph"
> wrote:
>
> >Convert your UDT to a Class.
> >For a "UDT Array" pass a Typed Collection Class.
>
> Thanks for responding, Ralph. Unfortunately, performance is an issue,
> and the VB collection object just doesn't cut it. There is a
> logarithmic increase in the time required to clear a collection, which
> I consider unacceptable for my purposes. In one notable case, the
> number of items exceeded 300,000 - way too many for a collection. The
> array barely handled it.
>

"Build a Collection that runs 100 times faster than the VB version and
enhance many controls with this code."
http://www.vbaccelerator.com/home/VB/Code/Techniques/Storing_Objects_Against_ItemData_and_Tag_Properties/article.asp
LinkedListLib
http://www.killervb.com/Libraries.aspx
A Fast Index-Based Collection
http://www.vbaccelerator.com/home/vb/Code/Techniques/A_Fast_Index-Based_Object_Collection/article.asp
Olaf's Dictionary-Implementation
www.datenhaus.de/Downloads/dhSortedDictionary.zip

hth
-ralph
Back to top
View user's profile Send private message
Jeremiah D. Seitz



Joined: 09 Jan 2008
Posts: 26

PostPosted: Wed Feb 06, 2008 4:31 pm    Post subject: Re: Aliasing a UDT Reply with quote

On Tue, 5 Feb 2008 22:30:15 -0600, "Ralph"
wrote:

>As Jim noted if this is something for a different "process" (program) then
>we are likely talking about else, but ... Passing a UDT as an Object will
>full-fill your object. (pun intended ) in either case.

That's a limitation I can live with. Most of the cases in which the
aliasing concept would be applied are within the same process.

>As for the problems with a VB Collection, you are correct. VB Collections
>are not known as being high performers. However, there are alternatives to
>the VB Collection which will do better. I'll fish about and see if I can't
>find a few URLs.

I've got plenty of code for that floating around. I appreciate your
looking, though.

>However, you can still benefit from a "Collection Class". If you aren't
>familiar with them just load up the VB Class Builder, create a simple class,
>and then create a Collection Class to wrap it. In the generated code you
>will see that it wraps a VB Collection. You do NOT have to use a VB
>Collection. You could substitute any kind of bag you wish. Either one the
>replacements or your original array.

That's actually where I was going with this whole thing. I'll be
wrapping the UDT array with a collection class, and implementing
NewEnum using the vbACOM library.

>From that point you can do practically anything to mangle its presentation
>for a client. You might use the default Interface to manage the 'wrapper'
>and then create an additional Interface to supply a simple 'UDT' for the
>client.

I'm currently doing that as well.

>Don't be alarmed at what might appear to be a 'large' object - at runtime
>only the Interfaces (vtables) and the Data is all that matters.
>
>Another thing you can try is to declare your Type in a type library. This is
>a way of getting around VB's restriction against Public UDTs. The problem is
>due to VB's way of defining 'public' values and essentially can't be alias'd
>in VB. Make sure the type lib is within scope of both the client and service
>and this will assist in removing some issues in passing UDTs, but you still
>have a problem with an array.

.... and that is where I am right now. My app works quite well, but I'm
a speed freak. Unfortunately, exposing the UDT as public doesn't
perform any input validation, certain fields could be read-only, etc.

I'd like to clarify that this is by no means something I *need*. It's
more of an idle question that. If I can find out how to do it, I'll be
able to implement the concept in many of my applications. Otherwise,
I'll consider it a good discussion.

>hth
>-ralph

Thanks again,

J.
Jeremiah D. Seitz
Omega Techware
http://www.omegatechware.net
Back to top
View user's profile Send private message
Jeremiah D. Seitz



Joined: 09 Jan 2008
Posts: 26

PostPosted: Wed Feb 06, 2008 4:33 pm    Post subject: Re: Aliasing a UDT Reply with quote

On Tue, 5 Feb 2008 22:00:32 -0500, "Jim Mack"
wrote:

>If you're literally talking about a separate process, then no. As you
>know, separate processes have separate memory spaces: anything shared
>between them must be marshalled across those spaces. And for a UDT
>that involves a deep copy. If the UDT contains objects, you're getting
>way complicated.

Separate processes would have been nice, but by no means necessary. As
to the UDT containing objects, the answer would be no. Just primitive
data types.

By "deep copy", I assume copying the entire structure?

>So, do you really mean separate processes? Because if you drop that
>requirement, what you want may be do-able. How easy it is depends on
>what the UDT contains.

Consider it dropped. Smile

J.
Jeremiah D. Seitz
Omega Techware
http://www.omegatechware.net
Back to top
View user's profile Send private message
Jeremiah D. Seitz



Joined: 09 Jan 2008
Posts: 26

PostPosted: Wed Feb 06, 2008 4:43 pm    Post subject: Re: Aliasing a UDT Reply with quote

On Wed, 6 Feb 2008 13:17:14 +0100, "Schmidt" wrote:

>Can you describe your current scenario a bit more
>detailed?

I don't have a specific scenario, but I can give you an example (air
code) :

'"Record" class
Option Explicit
Option Compare Text
Private Type RecordUDT
Name As String * 50
Number As Long
End Type
Private R As RecordUDT
Public Property Get Name() As String
Name = Trim(R.Name)
End Property
Public Property Get Number() As Long
Number = R.Number
End Property
Friend Function Initialize(ByVal Pointer As Long) As Boolean
'*** Alias R here ***
Initialize = True 'Assuming success
End Sub

'"Records" class
Option Explicit
Option Compare Text
Private Type RecordUDT
Name As String * 50
Number As Long
End Type
Private Records() As RecordUDT
Public Property Get Item(Byval Ordinal As Long) As Record
Dim RecordX As Record
Set RecordX = New Record
If RecordX.Initialize VarPtr(Records(Ordinal)) Then
Set Item = RecordX
End If
Set RecordX = Nothing
End Property

Obviously, the Records class would have a lot more to it, but that's
the basic idea. I'd like the variable "R" in the Record class to
actually point to the same data as "Records(Odinal)" in the Records
class.

>Olaf

J.
Jeremiah D. Seitz
Omega Techware
http://www.omegatechware.net
Back to top
View user's profile Send private message
Jim Mack



Joined: 04 Oct 2007
Posts: 735

PostPosted: Wed Feb 06, 2008 4:47 pm    Post subject: Re: Aliasing a UDT Reply with quote

Jeremiah D. Seitz wrote:

> By "deep copy", I assume copying the entire structure?

Yes, and if it contains arrays, the structure and content of the
arrays, etc. It means no pointers get copied literally, but what they
point to must itself be duplicated. Strings, arrays, objects and the
like.


>> So, do you really mean separate processes? Because if you drop that
>> requirement, what you want may be do-able. How easy it is depends
>> on what the UDT contains.
>
> Consider it dropped. Smile

Well, then I don't quite follow something you posted earlier, which is
that you don't seem to be able to pass a UDT variable ByRef. In my
experience, that's the only way VB will pass a variable of UDT. Can
you give an example?

The one time that VB will make a copy, even though it's passing ByRef,
is if the UDT contains string elements (VL or FL). It will make a
temporary copy with the string parts converted to Ansi.

There are at least two ways around that. One is to expose the UDT via
a typelib, and define those elements as BSTR. Another is to wrap it in
an array -- VB will convert an entire string array to Ansi if passed
to a Declared function, but will not convert the string elements of a
UDT contained in an array. Another is to define the string fields as
Variants of type String -- VB does not Ansi-convert strings passed
inside Variants.

Food for thought, let us know whether we're hitting your target.

--
Jim Mack
MicroDexterity Inc
www.microdexterity.com
Back to top
View user's profile Send private message
Schmidt



Joined: 04 Oct 2007
Posts: 806

PostPosted: Thu Feb 07, 2008 12:31 am    Post subject: Re: Aliasing a UDT Reply with quote

"Jeremiah D. Seitz" schrieb im Newsbeitrag@4ax.com...
> On Wed, 6 Feb 2008 13:17:14 +0100, "Schmidt" wrote:
>
> >Can you describe your current scenario a bit more
> >detailed?
>
> I don't have a specific scenario, but I can give you an
> example (air code) :
As your Cross-Process-Requirement seems to be
dropped, I'd recommend this example, I've written
some time ago:
www.datenhaus.de/Downloads/LightWeightCOM.zip

It follows basically the same approach you've posted,
but it doesn't need Array-Spanning using SafeArray-
Structures. Instead it simply uses global Arrays, which
are visible to both, the "List-Class" and also the
"SubElement-Class". Inside the Item-Property there's
basically the same thing going on - a new SubElement
is dynamically created, but instead of a Pointer there's
simply the current Array-Index passed into this small
ClassWrapper for your Array-TypeDef.

The example above demonstrates an Obj-hierarchy of:
Library
Books
Pages
Library as Root - creating 1000 Books - each Book creating
1000 Pages - (1Mio Entries over all) and this creation-process
is all done in ca. 1sec on a PIV 2.6GHz (2sec in the IDE).

Full 'For Each'-Enumeration (all Books, all Pages in the Books)
is done after 0.9sec (ca. 3sec in the IDE).

And finally; destroying the whole Hierarchy is taking only 0.08sec.

Another approach, to work around the weak destroy-
performance of VB-created Objects in the range of
> 100000 Objects is, to implement real lightweight Objects,
based on a Typelib-defined Interface - the principles of this
approach are well described in "The-Curland-Book" -
but maybe the faked-approach as in your posting or in
the download-link above, using dynamically created
VB-Objects, based on "normal" VB-ClassDefinitions is
sufficient in your case.

Another question is - if you really have to work with Data
in form of Records laying in the dimension of ca.300000
as you've posted before, why not use a (InMemory-)
database for this kind of task - there you'd have
advanced Filter- and Join-functionality using SQL, nice
Data-encapsulation-objects as e.g. Recordsets, etc.

Olaf
Back to top
View user's profile Send private message
Ken Halter



Joined: 04 Oct 2007
Posts: 4150

PostPosted: Wed Feb 06, 2008 3:47 pm    Post subject: Re: Aliasing a UDT Reply with quote

"Jeremiah D. Seitz" wrote in message @4ax.com...
>
> Unless I'm missing something, there is no intrinsic way to
> pass a UDT array ByRef. I end up with a copy of the array instead.
> What I'd really like is to pass a pointer to another process, and have
> that process be able to access the original UDT array.
>

Someone else may be able to describe exactly how many bytes are floating
around, but this code does pass an array of UDTs ByRef (there's no other
way, in this case ).... iow, the variables aren't re-allocated and
filled, they're using the same physical memory space as they were before
being passed....

One "gotchya" that goes with this snip is.... the Public UDT has to be
declared in a Public object module... which, all but eliminates the
possibility of making the declaration in a standard.exe (DLL/OCX/ActiveX EXE
projects are Ok... and this /may/ not work in VB5)

The easiest test project to start with (imo) would be a standard exe/DLL
group.
'==================================
Standard EXE - Form1 code
Form has a single command button to get
things going
'==================================
Option Explicit

Private Sub Command1_Click()
Dim i As Integer
Dim TheUDT As TestThisUDT
Dim SomeTests() As TestThisUDT
Dim oTheClass As Class1

'Look ma, no object instantiation!
'Makes sense, as far as VBs concerned, the UDT's declared
TheUDT.UDT1 = "This"
TheUDT.UDT2 = "That"
TheUDT.UDT3 = 123

Debug.Print TheUDT.UDT1, TheUDT.UDT2, TheUDT.UDT3

Debug.Print String$(60, "*")

'Pass an array to the class... ByRef
Set oTheClass = New Class1
ReDim SomeTests(4)

For i = 0 To 4
SomeTests(i).UDT1 = "Let's see what happens " & i
SomeTests(i).UDT2 = "VarPtr = " & VarPtr(SomeTests(i).UDT1)
SomeTests(i).UDT3 = i

Debug.Print SomeTests(i).UDT1 _
, SomeTests(i).UDT2 _
, SomeTests(i).UDT3

Next

Debug.Print String$(60, "*")

Call oTheClass.PassSomeUDTs(SomeTests)

Debug.Print String$(60, "*")

End Sub
'==================================
ActiveX DLL - Class1 code
'==================================
Option Explicit

Public Type TestThisUDT
UDT1 As String
UDT2 As String
UDT3 As Double
End Type

Public Sub PassSomeUDTs(ThisArray() As TestThisUDT)
Dim i As Integer
For i = LBound(ThisArray) To UBound(ThisArray)

'You'll see that the VarPtr's match here
Debug.Print ThisArray(i).UDT1 _
, ThisArray(i).UDT2, VarPtr(ThisArray(i).UDT1) _
, ThisArray(i).UDT3
Next
End Sub
'==================================

--
Ken Halter - MS-MVP-VB - Please keep all discussions in the groups..
In Loving Memory - http://www.vbsight.com/Remembrance.htm
Back to top
View user's profile Send private message
Jeremiah D. Seitz



Joined: 09 Jan 2008
Posts: 26

PostPosted: Wed Feb 06, 2008 7:00 pm    Post subject: Re: Aliasing a UDT Reply with quote

On Wed, 6 Feb 2008 08:58:18 -0600, "Ralph"
wrote:

>Olaf's Dictionary-Implementation
>www.datenhaus.de/Downloads/dhSortedDictionary.zip

This one is new to me. Thanks!

>hth
>-ralph

J.
Jeremiah D. Seitz
Omega Techware
http://www.omegatechware.net
Back to top
View user's profile Send private message
Jeremiah D. Seitz



Joined: 09 Jan 2008
Posts: 26

PostPosted: Wed Feb 06, 2008 7:05 pm    Post subject: Re: Aliasing a UDT Reply with quote

On Wed, 6 Feb 2008 11:47:22 -0500, "Jim Mack"
wrote:

>Yes, and if it contains arrays, the structure and content of the
>arrays, etc. It means no pointers get copied literally, but what they
>point to must itself be duplicated. Strings, arrays, objects and the
>like.

Gotcha.

>Well, then I don't quite follow something you posted earlier, which is
>that you don't seem to be able to pass a UDT variable ByRef. In my
>experience, that's the only way VB will pass a variable of UDT. Can
>you give an example?

Sure. Here you go :

Option ...
Private C as TestUDT
Public Sub SetInfo(UDTX As TestUDT)
C = UDTX
End Sub

Although the UDT is passed ByRef, changes to C won't affect the
variable originally passed.

>The one time that VB will make a copy, even though it's passing ByRef,
>is if the UDT contains string elements (VL or FL). It will make a
>temporary copy with the string parts converted to Ansi.

That might be where I'm going wrong. Many of my UDTs contain strings,
both fixed and variable.

>There are at least two ways around that. One is to expose the UDT via
>a typelib, and define those elements as BSTR. Another is to wrap it in
>an array -- VB will convert an entire string array to Ansi if passed
>to a Declared function, but will not convert the string elements of a
>UDT contained in an array. Another is to define the string fields as
>Variants of type String -- VB does not Ansi-convert strings passed
>inside Variants.

I'll have to look into that, and I'll report back when I have some
results.

>Food for thought, let us know whether we're hitting your target.

It seems like I'm getting the information I need, even if it's
information I don't want to hear. Smile

Thanks again,

J.
Jeremiah D. Seitz
Omega Techware
http://www.omegatechware.net

Back to top
View user's profile Send private message
Display posts from previous:   
Related Topics:
Determining jpeg size Hello, In vb6, is it possible to determine the pixel size of an image (such as a jpeg or bmp)? ie. if I retrieve the path and file name of the image using a commondialog box, can I somehow retrieve the image's pixel width and height: myImageWidth = ?? my

mstfqws.pdw error What' s mstfqws.pdw error ??? It occurs when I run my setup file Thanks in advance Serdar

Dir function I can easily use the dir function to get all the files in a particular directory on a drive. But how do I easily get ALL the files in ALL the directories on a selected drive? Thanks

Overlay image on Movie I am trying to draw some boxes or circles on the movie window. I tried to overlay a transparent picture-box window on the movie window, the Media Player object. But it did not work. Actually, this job can be easily done using VMR in DirectX. However, in c

Preferred syntax multiple if I have seen it sometimes advised to avoid (where possible): - Nested ifs - GoTo's with that in mind, if you have the following multiple tests as a requirement .... 'nested ifs version For Each oObj In Collection If oObj.Prop1 Like sProp Then If TypeOf oOb
Post new topic   Reply to topic    msvisual.com Forum Index -> VB WinAPI All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group