 |
| Pro VB 6 For advanced Visual Basic coders working in version 6 (not .NET). Beginning-level questions will be redirected to other forums, including Beginning VB 6. |
Welcome to the p2p.wrox.com Forums.
You are currently viewing the Pro VB 6 section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
|
|
|
|

February 18th, 2004, 06:52 AM
|
|
Authorized User
|
|
Join Date: Jan 2004
Posts: 60
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
John and Marco,
Thanks. Let me see if I have understood the problem of circular references. I am going to describe two approaches. It helps to draw a diagram of each.
Approach 1 - Using a circular reference.
----------------------------------------------------------------------
I create Class A by a call from my spreadsheet. That gives me a pointer to it (let's call it A1).
Class A creates Class B and points to it (let's call the pointer B1). Class B sets a pointer back to Class A (let's call it A2).
Now:
If I set A1 to nothing, Class A is not destroyed because A2 still exists. There is now a BIG problem, because I cannot talk to Class A, and can therefore not get to Class B either. So it becomes impossible to destroy either.
What I would NEED to do instead would be to FIRST set B1 to nothing. This would destroy Class B and therefore A2 would no longer exist (I THINK that is right but correct me if I am wrong). I could now safely set A1 to nothing. All is now destroyed.
So... there is a solution to "tidying up" circular references, but you have to be careful what order you do things in.
Approach 2 - Using a third class to avoid a circular referefnce
----------------------------------------------------------------------
I create Class A by a call from my spreadsheet. That gives me a pointer to it (let's call it A1).
Class A creates Class C and points to it (let's call the pointer C1).
Class A creates Class B and points to it (let's call the pointer B1). Class B sets a pointer to Class C (let's call it C2).
Now:
If I set A1 to nothing, Class A is destroyed. Therefore, pointers B1 and C1 no longer exist. Since B1 does not exist, then Class B is destroyed. Therefore, C2 does not exist. Since C1 and C2 no longer exist, Class C is destroyed.
So... in one action (setting A1 to nothing) I have destroyed everything. Therefore this is better than using a circular reference.
---------------
Is the above analysis of the two approaches correct, or have I mis-understood anything?
I would be grateful if you could let me know. I know this is basic stuff, but sometimes if we mis-understand the basics, we get into real trouble!
Many thanks.
James
|
|

February 18th, 2004, 07:12 AM
|
|
Authorized User
|
|
Join Date: Jan 2004
Posts: 60
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
John and Marco,
...and, on a related issue:
I want my spreadsheet to say "go" to the DLL, and have the DLL do everything. That is, I will create an instance of Class A (in the DLL) which will then busy itself with ALL the calculations I need to have done, before passing its results back to the spreadsheet.
So... I want Class A to act as the controller that "pulls the strings" and creates all the other classes to be used, and manipulates them all as required. My other option would be to control all the classes from the VBA that I write in my spreadheet - but I don't want to do that because I want to keep the VBA down to an absolute minimum and "hide" all my code in the DLL (as the code will be commercially sensitive).
Class A is therefore acting a bit like a "main" function in a VB application.
Is this the correct way to do this, or is there another approach?
Thanks.
James
|
|

February 18th, 2004, 11:01 AM
|
|
Friend of Wrox
|
|
Join Date: Jun 2003
Posts: 101
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
I know this took a lot of conversation, bt it sounds to me like you have a grasp on it.
This would have been so much easier if we had a way to draw pictures. :)
John R Lick
[email protected]
|
|

February 18th, 2004, 11:22 AM
|
|
Authorized User
|
|
Join Date: Jan 2004
Posts: 60
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Thanks, John.
What do you think about my other post, about Class A acting as my "main" function?
|
|

February 18th, 2004, 11:29 AM
|
|
Friend of Wrox
|
|
Join Date: Jun 2003
Posts: 101
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
I was responding to both. I think that you have a good handle on things. I would definately map all the objects (and pointers) out, just to help keep them straight. I personally like UML, but I only put the important stuff in the diagrams.
It looks to me like you have worked in other languages, since grasp that you are using pointers in VB, even though you don't directly access them that way. I have found that with OOP in VB, people who have a grasp on pointers understand how it works better. VB hides so much to "make it easier", that people who have only worked in VB commonly have difficulties understanding how things work.
John R Lick
[email protected]
|
|

February 18th, 2004, 12:29 PM
|
|
Authorized User
|
|
Join Date: Jan 2004
Posts: 60
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Thank you, John.
I have previously programmed in C++ (OOP) so am more familiar with that than VB. To be honest, I am feeling my way with VB - but I know from experience that if you get ahead of yourself in an unfamiliar language, it can really trip you up later. It's best to do things correctly from the start. That's why I am pestering this forum with questions :)
Many thanks for your help with this.
James
|
|

February 18th, 2004, 02:54 PM
|
|
Friend of Wrox
|
|
Join Date: Jun 2003
Posts: 627
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Hi James,
I could have written your same post five or six years ago... The main problem with (us) C programmers is that we are too much used to pointers and because of that think that VB stinks. And all because we do not know how to do it something that we know perfectly well how to do it in C. Let's give VB its credits: when used the right way is just another programming language.
I completely agree that classA *must* be the main controller. The client should be completeley ignorant about what is going on, besides that fact that your dll can be changed any time without affecting any of its clients.
Regarding destroying classB before classA, well it can be done only if the client knows about classB, and this is absolutely not a good idea. One of the suggested methods to repair circular reference is to have all classes implementing a Terminate method. The main client before setting the main class to nothing *must* call its Terminate. In turn, classA calls the Terminate of all the created classes before setting them to nothing. It works, but is 1) a nightmare to maintain and 2) the client must have the knowledge of Terminate.
Well, what the hell, I will tell another crazy idea. Create a dll in C++, and in the classB pass to it its reference to classA. In the dll, because it is written in C++, you can access the referenceCount of the IUnknown interface of classB, and decrement it. As I saied, it is a crazy idea (it is called stolen reference), but someone published it. And the most beautiful of all them: instead of creating a reference using the Set statement, copy the address of your classC using the CopyMemory API (weak reference)... stop for now.
Have fun,
Marco
Quote:
quote:Originally posted by James Diamond
Thank you, John.
I have previously programmed in C++ (OOP) so am more familiar with that than VB. To be honest, I am feeling my way with VB - but I know from experience that if you get ahead of yourself in an unfamiliar language, it can really trip you up later. It's best to do things correctly from the start. That's why I am pestering this forum with questions :)
Many thanks for your help with this.
James
|
|
|

February 19th, 2004, 08:53 AM
|
|
Authorized User
|
|
Join Date: Jan 2004
Posts: 60
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Marco,
Thanks.
After all our discussions, I think I understand things more clearly. Ironically, I have decided to use circular references for all my classes contained by Class A. That is, for each contained class, it is going to receive a pointer back to Class A. This will enable ANY contained class to talk to any other contained class via Class A.
Then, when I come to clean up, I will call a CleanUp() function in Class A. This will set all of Class A's class pointers to nothing. I will then set the Class A pointer (in the client) to nothing. (I realise that each of the contained classes may point to other classes, and therefore will need their own CleanUp() functions). This is obviously the same as the Terminate methods you describe. I am happy to do this, as it seems the cleanest way for the contained classses to communicate with each other. Otherwise, how can contained Class X talk to contained class Y without a similar issue of circular references arising? I do not want a "spaghetti" of pointers between all the contained classes of Class A. That is why I think I should do all communications via Class A.
What do you think?
James
|
|

February 19th, 2004, 02:09 PM
|
|
Friend of Wrox
|
|
Join Date: Jun 2003
Posts: 627
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
This is my personal story.
One of my first VB projects was a simple exe. It was so much of a
success that I continued adding features and features, that means adding more and more classes etc. Lot of circular references that at that time I did not know anything about. Then lighting stroke: change the exe into an ocx so we could add it anywhere. It was a disaster... After a web search and more reading (VBPJ) I added the Terminate (like your CleanUp) methods, and now finally it was working again, but for short time, because soon after I received calls that the application was not dying (again). This is because someone modified the project (again), forgot to add code in the Terminate methods and everything was in hell again. And this happened many time after... Remember Murphy: even the worst possibility will be a reality.
Now I am responsible of tens of ActiveX projects, and I tell you: I NEVER put another circular reference! As soon as I start a new project, right away I create a CParams class, where I put all my "global" variables (user settings, for example), and I pass it around. If you are still confused drop me an email (click on my user profile) and I will email you a zipped example.
Marco
Quote:
quote:Originally posted by James Diamond
Marco,
Thanks.
After all our discussions, I think I understand things more clearly. Ironically, I have decided to use circular references for all my classes contained by Class A. That is, for each contained class, it is going to receive a pointer back to Class A. This will enable ANY contained class to talk to any other contained class via Class A.
Then, when I come to clean up, I will call a CleanUp() function in Class A. This will set all of Class A's class pointers to nothing. I will then set the Class A pointer (in the client) to nothing. (I realise that each of the contained classes may point to other classes, and therefore will need their own CleanUp() functions). This is obviously the same as the Terminate methods you describe. I am happy to do this, as it seems the cleanest way for the contained classses to communicate with each other. Otherwise, how can contained Class X talk to contained class Y without a similar issue of circular references arising? I do not want a "spaghetti" of pointers between all the contained classes of Class A. That is why I think I should do all communications via Class A.
What do you think?
James
|
|
|

February 24th, 2004, 06:42 AM
|
|
Authorized User
|
|
Join Date: Jan 2004
Posts: 60
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Marco,
This is all very well, but is not exactly OOP - in which data and methods are encapsulated in a class. There is nothing wrong with creating a "global variables" class, but that's not really what I need. What I need are classes that encapsulate their own private data and methods, and I need those classes to be able to talk to each other. From what you are saying, it seems that (withEvents aside) VB does not make such a process possible without circular references (and potential memory leaks if cleanups are not rigorously adhered to). Surely this is crazy?
Can anyone else give an opinion on this issue, please?
Thanks.
James
|
|
 |