 |
|
|
|
| Author |
Message |
Jeremiah D. Seitz
Joined: 09 Jan 2008 Posts: 26
|
Posted: Wed Feb 06, 2008 12:26 am Post subject: Aliasing a UDT |
|
|
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 |
|
 |
Ralph
Joined: 04 Oct 2007 Posts: 4148
|
Posted: Wed Feb 06, 2008 12:00 am Post subject: Re: Aliasing a UDT |
|
|
"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 |
|
 |
Jeremiah D. Seitz
Joined: 09 Jan 2008 Posts: 26
|
Posted: Wed Feb 06, 2008 1:53 am Post subject: Re: Aliasing a UDT |
|
|
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 |
|
 |
Jim Mack
Joined: 04 Oct 2007 Posts: 735
|
Posted: Wed Feb 06, 2008 3:00 am Post subject: Re: Aliasing a UDT |
|
|
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 |
|
 |
Ralph
Joined: 04 Oct 2007 Posts: 4148
|
Posted: Wed Feb 06, 2008 3:30 am Post subject: Re: Aliasing a UDT |
|
|
"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 |
|
 |
Schmidt
Joined: 04 Oct 2007 Posts: 806
|
Posted: Wed Feb 06, 2008 6:17 pm Post subject: Re: Aliasing a UDT |
|
|
"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 |
|
 |
Ralph
Joined: 04 Oct 2007 Posts: 4148
|
|
| Back to top |
|
 |
Jeremiah D. Seitz
Joined: 09 Jan 2008 Posts: 26
|
Posted: Wed Feb 06, 2008 4:31 pm Post subject: Re: Aliasing a UDT |
|
|
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 |
|
 |
Jeremiah D. Seitz
Joined: 09 Jan 2008 Posts: 26
|
Posted: Wed Feb 06, 2008 4:33 pm Post subject: Re: Aliasing a UDT |
|
|
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.
J.
Jeremiah D. Seitz
Omega Techware
http://www.omegatechware.net |
|
| Back to top |
|
 |
Jeremiah D. Seitz
Joined: 09 Jan 2008 Posts: 26
|
Posted: Wed Feb 06, 2008 4:43 pm Post subject: Re: Aliasing a UDT |
|
|
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 |
|
 |
Jim Mack
Joined: 04 Oct 2007 Posts: 735
|
Posted: Wed Feb 06, 2008 4:47 pm Post subject: Re: Aliasing a UDT |
|
|
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.
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 |
|
 |
Schmidt
Joined: 04 Oct 2007 Posts: 806
|
Posted: Thu Feb 07, 2008 12:31 am Post subject: Re: Aliasing a UDT |
|
|
"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 |
|
 |
Ken Halter
Joined: 04 Oct 2007 Posts: 4150
|
Posted: Wed Feb 06, 2008 3:47 pm Post subject: Re: Aliasing a UDT |
|
|
"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 |
|
 |
Jeremiah D. Seitz
Joined: 09 Jan 2008 Posts: 26
|
Posted: Wed Feb 06, 2008 7:00 pm Post subject: Re: Aliasing a UDT |
|
|
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 |
|
 |
Jeremiah D. Seitz
Joined: 09 Jan 2008 Posts: 26
|
Posted: Wed Feb 06, 2008 7:05 pm Post subject: Re: Aliasing a UDT |
|
|
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.
Thanks again,
J.
Jeremiah D. Seitz
Omega Techware
http://www.omegatechware.net
|
|
| Back to top |
|
 |
|
|
| 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 |
|
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
|