Wrox Programmer Forums

Need to download code?

View our list of code downloads.

Go Back   Wrox Programmer Forums > Visual Basic > VB 6 Visual Basic 6 > Pro VB 6
Password Reminder
Register
Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read
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 tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developersí questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
Reply
 
Thread Tools Display Modes
  #1 (permalink)  
Old February 17th, 2004, 11:13 AM
Authorized User
 
Join Date: Jan 2004
Location: , , .
Posts: 60
Thanks: 0
Thanked 0 Times in 0 Posts
Default Talking classes in VB6

I have written a DLL in VB6 containing two classes, a public class A and a private class B.

I have a spreadsheet that creates an instance of class A.

Class A creates an instance of class B.

Class B needs to talk back to class A, but I do not know how class B can know the name of class A in order to talk to it.

Please can you tell me how to do this?

Thanks.

James

//##

Reply With Quote
  #2 (permalink)  
Old February 17th, 2004, 11:33 AM
Friend of Wrox
 
Join Date: Jun 2003
Location: Sparks, NV, USA.
Posts: 101
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via MSN to jlick
Default

There are two ways, depending on what your needs are:

  1) You could pass a reference of A to B.
  2) You could have B raise an event.

I have included samples of both. I have not tested this from MS-Excel, but it should work fine. I have tested in the VB IDE, but didn't compile.

Class A:
Code:
Option Explicit

Private WithEvents m_classB As B
Private m_valueOfB As Long

Public Sub Add10ToBsValue()
    If m_classB Is Nothing Then
        Set m_classB = New B
    End If

    m_classB.AddTenWithCallBack Me
    m_classB.AddTenWithEvent

End Sub

Public Sub CallBackFromB(ByVal a_valueOfB As Long)
    m_valueOfB = a_valueOfB
    MsgBox m_valueOfB
End Sub

Private Sub m_classB_ChangeToValueOfB(ByVal a_newValue As Long)
    m_valueOfB = a_newValue
    MsgBox m_valueOfB
End Sub
Class B:
Code:
Option Explicit

Public Event ChangeToValueOfB(ByVal a_newValue As Long)

Private m_myValue As Long

Public Sub AddTenWithCallBack(ByRef a_classA As A)
    m_myValue = m_myValue + 10
    a_classA.CallBackFromB m_myValue
End Sub

Public Sub AddTenWithEvent()
    m_myValue = m_myValue + 10
    RaiseEvent ChangeToValueOfB(m_myValue)
End Sub
Is this a re-post?


John R Lick
JohnRLick@hotmail.com
Reply With Quote
  #3 (permalink)  
Old February 17th, 2004, 11:44 AM
Friend of Wrox
 
Join Date: Jun 2003
Location: Sparks, NV, USA.
Posts: 101
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via MSN to jlick
Default

James,

You should read the reply from marcostraf in your post of the same problem in Beginning_VB.

There is another problem that Marco didn't talk about. If I understand you want the following

SpreadSheet -> ClassA -> ClassB
                 ^ |
                 L---------+

Meaning Your SpreadSheet references ClassA, ClassA references ClassB, and ClassB references ClassA.

If you keep the reference from ClassB to ClassA (module level variable), then you have a circular reference between ClassA & ClassB. Then when your spreadsheet tries to destroy ClassA, it doesn't get destroyed, because COM sees that ClassA is still being referenced (by ClassB). Now you have a memory leak.

I would suggest that you give more details about what it is that you are REALLY trying to do, and we can give better advise.


John R Lick
JohnRLick@hotmail.com
Reply With Quote
  #4 (permalink)  
Old February 17th, 2004, 11:45 AM
Friend of Wrox
 
Join Date: Jun 2003
Location: Sparks, NV, USA.
Posts: 101
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via MSN to jlick
Default

Sorry characters didn't line up, lets try again...

Code:
SpreadSheet -> ClassA -> ClassB
                 ^         |
                 L---------+
John R Lick
JohnRLick@hotmail.com
Reply With Quote
  #5 (permalink)  
Old February 17th, 2004, 12:12 PM
Authorized User
 
Join Date: Jan 2004
Location: , , .
Posts: 60
Thanks: 0
Thanked 0 Times in 0 Posts
Default

John,

Thanks for replying.

Yes, this is a re-post because my previous thread became horribly confused. (For reference, it is here: http://p2p.wrox.com/topic.asp?TOPIC_ID=9609)

My problem is really stated as clearly as possible here.

I know about the circular reference issue (which occurs in your use of AddTenWithCallBack). That is what I want to avoid, as I am told it is bad practice and can lead to unwanted objects in memory.

"RaiseEvent" is new to me. Does this solve the circular reference issue?

I need to know the standard, accepted, best practice to do this. Please can you tell me if using RaiseEvent is the best practice? Or are there other ways?

I am anxious to find the right way to do this as soon as possible, as it is preventing me from continuing development.

Thanks.
Reply With Quote
  #6 (permalink)  
Old February 17th, 2004, 12:17 PM
Friend of Wrox
 
Join Date: Jun 2003
Location: Sparks, NV, USA.
Posts: 101
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via MSN to jlick
Default

It really depends on what it is that you are trying to do. RaiseEvent will not create a circular reference, but any object that has a reference to the instance of B that raises the event will get the event. Meaning if C also has a reference to the same instance of B that A does, then both A & C would get the event.

Again, what are you trying to do? I am pretty sure you don't have a business requirement that say object B needs a reference to object A.


John R Lick
JohnRLick@hotmail.com
Reply With Quote
  #7 (permalink)  
Old February 17th, 2004, 12:27 PM
Authorized User
 
Join Date: Jan 2004
Location: , , .
Posts: 60
Thanks: 0
Thanked 0 Times in 0 Posts
Default

John,

Yes - I have a business requirement for this.

My spreadsheet creates an instance of Class A to start things off in the DLL. As far as I know, that is the only way my spreadsheet can begin the DLL "doing its stuff". But please tell me if there is another way.

So... the instance of Class A manipulates some data and stores it privately. One of those pieces of private data is an instance of Class B (required because it is really a collection of related variables). So it creates an instance of Class B.

In fact, my DLL will require many classes to be created, and these WILL need to talk to each other. Surely it is a standard programming requirement for instances of classes to call each other's methods.... the problem is that I don't see how Class B can refer to Class A (or indeed for other classes to talk to each other) without creating circular references.

I am SURE that this is a basic issue (I am pretty new to VB) and really I just need someone to tell me how to do this. I am really surprised that I have not been given a "quick" solution for this. I am grateful to you for your input, and for the RaiseEvent possibility, but need to find out if that is the only (and best) way of doing this.

Many thanks.

James
Reply With Quote
  #8 (permalink)  
Old February 17th, 2004, 01:09 PM
Friend of Wrox
 
Join Date: Jun 2003
Location: Sparks, NV, USA.
Posts: 101
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via MSN to jlick
Default

The last information you gave me was very helpful.

There are many ways for classes to talk to each other. You can have public properties on ClassB that ClassA can check. You can have return values from methods on ClassB that return information to ClassA. You can have events on ClassB that get raised. The issue with events in VB6 (not an issue in .Net) is that to have ClassB raise events to ClassA, ClassB has to be a module level variable in ClassA.

You can pass in a reference of ClassA to ClassB, but that is circular.

What I try to do is have the instantiating class act as the organizer. For example, if ClassA asks ClassB to do something, (that changes many variables) then After control comes back to ClassA, it should check ClassB for the relavant changes. This is classic OOP.

For example, if you have a Dog Class and a Tail Class. You would want the dog class to tell the Tail Class to wag. Then have the Dog Class check the state of the Tail Class.

Or if you have an Order object that has many Item objects, you may want to have the Order object tell the Item objects to calculate their individual Taxes. Then have the Order object total them, for the overall tax of the order.

This would be done by having the Item Class having a public property call TaxAmount. (The property could calculate the tax on the fly, or you could have a method to calculate the tax.) But the key is that the Order object is really in control.

You have to approach this problem differently in a distributed environment, but it doesn't sound like you are working in a distributed environment.



John R Lick
JohnRLick@hotmail.com
Reply With Quote
  #9 (permalink)  
Old February 17th, 2004, 02:49 PM
Friend of Wrox
 
Join Date: Jun 2003
Location: Alameda, ca, USA.
Posts: 627
Thanks: 0
Thanked 0 Times in 0 Posts
Default

John,

I agree with you and I would like to comment your line:

"For example, if ClassA asks ClassB to do something, (that changes many variables) then After control comes back to ClassA, it should check ClassB for the relavant changes."

This works only if ClassA knows the lifespan of classB. If classA creates classB and then leaves it on its own, than ClassB must have a way to communicate back to classA. Creating ClassB withevents is a solution to avoid circular reference, but I perfer the 'intermediate' class.

Let's say that ClassA has a variable (m_var) that some other classes need to manipulate. This is James's problem. Instead of declaring m_var in ClassA, I create a new class (ClassC) and there I declare m_var. I can make it exposed via Let/Set/Get properties, so I have control on what is going on (like I can validate its value, regradless on who is trying to modify it)

Now, ClassA creates ClassC, and thus it can access m_var. When classA creates classB, it passes ClassC to it. At this point both ClassA and ClassB can pint to the same variable, and no circular reference is created.

I uses this tecnique in almost all my projects, and so far is working great.

Marco


Quote:
quote:Originally posted by jlick
 The last information you gave me was very helpful.

There are many ways for classes to talk to each other. You can have public properties on ClassB that ClassA can check. You can have return values from methods on ClassB that return information to ClassA. You can have events on ClassB that get raised. The issue with events in VB6 (not an issue in .Net) is that to have ClassB raise events to ClassA, ClassB has to be a module level variable in ClassA.

You can pass in a reference of ClassA to ClassB, but that is circular.

What I try to do is have the instantiating class act as the organizer. For example, if ClassA asks ClassB to do something, (that changes many variables) then After control comes back to ClassA, it should check ClassB for the relavant changes. This is classic OOP.

For example, if you have a Dog Class and a Tail Class. You would want the dog class to tell the Tail Class to wag. Then have the Dog Class check the state of the Tail Class.

Or if you have an Order object that has many Item objects, you may want to have the Order object tell the Item objects to calculate their individual Taxes. Then have the Order object total them, for the overall tax of the order.

This would be done by having the Item Class having a public property call TaxAmount. (The property could calculate the tax on the fly, or you could have a method to calculate the tax.) But the key is that the Order object is really in control.

You have to approach this problem differently in a distributed environment, but it doesn't sound like you are working in a distributed environment.



John R Lick
JohnRLick@hotmail.com
Reply With Quote
  #10 (permalink)  
Old February 17th, 2004, 02:52 PM
Friend of Wrox
 
Join Date: Jun 2003
Location: Sparks, NV, USA.
Posts: 101
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via MSN to jlick
Default

Great Point, and I agree.

John R Lick
JohnRLick@hotmail.com
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
Converting VB6 classes to VB.NET (2003) jorgefejr VB How-To 2 August 25th, 2006 05:09 PM
talking to all txtBoxes via loop Loralee Access 11 October 7th, 2005 11:02 PM
talking to ms outlook from app wildt ASP.NET 1.x and 2.0 Application Design 0 March 24th, 2005 12:05 PM
Classes in VB6 - Urgent help required please James Diamond Pro VB 6 0 February 10th, 2004 10:42 AM
Call VB6 or VC++ classes from C# - Reflection? lpinho C# 0 September 22nd, 2003 09:44 AM



All times are GMT -4. The time now is 03:49 PM.


Powered by vBulletin®
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.