Hi guys,
I've been struggling for days to do this.

I've got 2 form. The first form (Form1) is to assign a variable (Result) a value. Another form (DisplayResult) is to display out the value.

Actually, my purpose is to learn how i can use global variables to share information between multiple forms and files, as well as to WATCH the value in Debug mode.

The problem I'm facing are:
1) In Form1, I assign 10 to Result. But in DisplayResult, it display Result as 0.
2) I can't seem to view the Result variable in watch window in Debug mode.

I've spend days in trying to find solution to it. Please advice.

I tried to upload the Visual Studio 2008 project but for some reason it failed. So I upload it to http://ifile.it/sf0kglz instead.

Thanks.

Recommended Answers

All 9 Replies

Hi,

This could be a timing issue that the display Form is called before the value updated by Form1. or my understanding is wrong here.

Are you opening the display form after the update (i mean step1 : 1) In Form1, I assign 10 to Result. But in DisplayResult, it display Result as 0.)

Can you paste the code here? please.

BR/ KMat

Hi guys,
I've been struggling for days to do this.

I've got 2 form. The first form (Form1) is to assign a variable (Result) a value. Another form (DisplayResult) is to display out the value.

Actually, my purpose is to learn how i can use global variables to share information between multiple forms and files, as well as to WATCH the value in Debug mode.

The problem I'm facing are:
1) In Form1, I assign 10 to Result. But in DisplayResult, it display Result as 0.
2) I can't seem to view the Result variable in watch window in Debug mode.

I've spend days in trying to find solution to it. Please advice.

I tried to upload the Visual Studio 2008 project but for some reason it failed. So I upload it to http://ifile.it/sf0kglz instead.

Thanks.

Below is the code.
Hope that helps.
Thanks.

// Static.cpp : main project file.

#include "stdafx.h"
#include "Form1.h"
#include "DisplayResult.h"
#include "GlobalVariables.h"

using namespace Static;
using namespace ProjectVariables;

[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
	// Enabling Windows XP visual effects before any controls are created
	Application::EnableVisualStyles();
	Application::SetCompatibleTextRenderingDefault(false); 

	// Create the main window and run it
	Application::Run(gcnew Form1());
	return 0;
}

void Static::Form1::ButtonClick()
{
	Result = 10;

	DisplayResult^ a=gcnew DisplayResult();
	a->Show();
}
// Form1.h
// MAIN FORM - ASSIGN RESULT
#pragma once

namespace Static {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;
	

	/// <summary>
	/// Summary for Form1
	///
	/// WARNING: If you change the name of this class, you will need to change the
	///          'Resource File Name' property for the managed resource compiler tool
	///          associated with all .resx files this class depends on.  Otherwise,
	///          the designers will not be able to interact properly with localized
	///          resources associated with this form.
	/// </summary>
	public ref class Form1 : public System::Windows::Forms::Form
	{
	public:
		Form1(void)
		{
			InitializeComponent();
			//
			//TODO: Add the constructor code here
			//
		}

	protected:
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		~Form1()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::Button^  button1;
	protected: 

	private:
		/// <summary>
		/// Required designer variable.
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		void InitializeComponent(void)
		{
			this->button1 = (gcnew System::Windows::Forms::Button());
			this->SuspendLayout();
			// 
			// button1
			// 
			this->button1->Location = System::Drawing::Point(60, 50);
			this->button1->Name = L"button1";
			this->button1->Size = System::Drawing::Size(94, 23);
			this->button1->TabIndex = 0;
			this->button1->Text = L"Assign Result";
			this->button1->UseVisualStyleBackColor = true;
			this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
			// 
			// Form1
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(284, 262);
			this->Controls->Add(this->button1);
			this->Name = L"Form1";
			this->Text = L"Form1";
			this->ResumeLayout(false);

		}
#pragma endregion

	private: 
		void ButtonClick();
	private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
			ButtonClick();
			 }
	};
}
// DisplayResult.cpp
// Display Result
#include "StdAfx.h"
#include "DisplayResult.h"
#include "GlobalVariables.h"

using namespace ProjectVariables;

void Static::DisplayResult::ButtonClick()
{

	String^ s = String::Format("{0}",Result);
	MessageBox::Show(s);
}
// DisplayResult.h
// SECOND FORM - DISPLAY RESULT
#pragma once

using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;


namespace Static {

	/// <summary>
	/// Summary for DisplayResult
	///
	/// WARNING: If you change the name of this class, you will need to change the
	///          'Resource File Name' property for the managed resource compiler tool
	///          associated with all .resx files this class depends on.  Otherwise,
	///          the designers will not be able to interact properly with localized
	///          resources associated with this form.
	/// </summary>
	public ref class DisplayResult : public System::Windows::Forms::Form
	{
	public:
		DisplayResult(void)
		{
			InitializeComponent();
			//
			//TODO: Add the constructor code here
			//
		}

	protected:
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		~DisplayResult()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::Button^  button1;
	protected: 

	private:
		/// <summary>
		/// Required designer variable.
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		void InitializeComponent(void)
		{
			this->button1 = (gcnew System::Windows::Forms::Button());
			this->SuspendLayout();
			// 
			// button1
			// 
			this->button1->Location = System::Drawing::Point(61, 48);
			this->button1->Name = L"button1";
			this->button1->Size = System::Drawing::Size(110, 23);
			this->button1->TabIndex = 0;
			this->button1->Text = L"Display Result";
			this->button1->UseVisualStyleBackColor = true;
			this->button1->Click += gcnew System::EventHandler(this, &DisplayResult::button1_Click);
			// 
			// DisplayResult
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(284, 262);
			this->Controls->Add(this->button1);
			this->Name = L"DisplayResult";
			this->Text = L"DisplayResult";
			this->ResumeLayout(false);

		}
#pragma endregion
	private:
		void ButtonClick();
	private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
				ButtonClick();
			 }
	};
}
// GlobalVariables.h
#pragma once

namespace ProjectVariables
{
	static int Result;
}

I've found a solution by using singleton as per the post here.
but then i read elsewhere that it is not advisable to use singleton.

Now i'm lost.. which is he best way to declare and use global variables/function to share information between few forms, threads etc. The variables can be made up of classes, strucs, string^, int^ etc..

Please advice.. thanks..

You specified your global variable with the keyword "static" which means that the global variable is local to the compilation unit it which it appears (a compilation unit is one compiled .cpp file). This means that the "global" variable Result that appears in "DisplayResult.cpp" is not the same as the global variable Result that appears in "Static.cpp".

To fix that problem, you would need to make the following code:

// GlobalVariables.h
#pragma once

namespace ProjectVariables
{
	extern int Result;
}
// GlobalVariables.cpp
#include "GlobalVariables.h"

namespace ProjectVariables
{
	int Result = 0;
}

(and add that cpp file to the project).


As per singletons, you are right that singletons are not recommended in general, but that's only because singletons are a form of global variables (albeit safer to use than global variables), and global variables are not recommended in general either. Singletons are better than global variables for sure, but neither are recommended.


>>which is he best way to declare and use global variables/function to share information between few forms, threads etc. The variables can be made up of classes, strucs, string^, int^ etc..

There are various "solutions" to this, most of the good ones involve redesigning your application with a better philosophy to begin with, and amongst the worse ones that are used with redesign fails or is not an option usually fall under two categories, "singletons" and "fly-weights". The former you already know about, that is, a singleton is just a way to create a global bundle of data (and related functionality) that can be safely accessed for everywhere in the code at anytime (unless there are competing threads). The latter (fly-weight) is simply to bundle all the "global" data into some object which carried through (by reference or pointer) to all the function calls that require it.

But the recommended solutions will involve rethinking the application. The idea "to share information between forms or threads" is ambiguous at best, and shows a lack of structure in your code. Usually, well-designed software involves a design of ownership of the information and responsabilities. When you properly design with ownership in mind (e.g. asking: "who should own this data? And why?", "who creates this data?", "who uses this data? and how?", "to what is this data's life-time linked to?", etc.), you rarely end up needing global data at all (e.g. the answers to those questions are rarely: "everything needs this data, it creates itself, it needs to exist as long as the program exists, etc.", which is really the only time when global variables or singletons are necessary). You should read my tutorial on design for ownership (note it is in C++, not the C++/CLI that you are using).

Thanks.
Read through your tutorial.
But I cannot seem to get my mind around to understand how to apply it.


Lets say I am writing a program to:
1) retrieve data from server when the program is started
2) forms where user can view and change data.
3) program will automatically save data to server every hour-backgroundworker.


I will need a class forexample "DATA" to store the information right?
In this case, the "DATA" will need to be ready when the program is started so that the forms can use it. If it is not global variables, or singleton, then how can i share it between 2 forms and another backgroundworker thread which saves data to server as well as other processing?
Hope you can spare some time in advising me.
I've been doing some reading, testing and some mental acrobatic to come out with the correct design for days but i'm still abit lost in the dark.

Hope you can spare me some time in guiding me.
Thanks alot..

What you are describing is a classic MVC (i.e. "Model-View-Controller") design pattern.

If you look at what your application is supposed to do from start to finish, it will look something like this:
1) Load some configurations describing how to connect to the data-server.
2) Establish a connection to the server.
3) Download all relevant information from the data-server.
4) Create a Viewer-Controller to display and modify the data somehow.
5) Buffer all the changes to the data.
6) Upload the data to the server every hour or so.
(When finished)
7) Destroy the Viewer-Controller.
8) Disconnect (log-out) from the data-server.
9) Terminate the application.

To me, it is pretty obvious that the Viewer-Controller (whether separate or together) require the existence of the "Model" to function (the "Model" in this case is the data streamer that buffers the data from the server). However, it is clear also that neither the Viewer nor the Controller should own the Model (the Model is created independently of the Viewer and Controller). This also opens the door to having multiple Viewers or Controllers, which can be a very nice feature.

It is also clear that the existence of the Model is not tied directly to the life-time of the program, it is tied to the availability of a connection to the server (or the necessary configuration to set-up one). You need to first collect the necessary configuration information before you can create the data-streamer for your application. That info is either collected from a config-file, or hard-coded, or the user is prompted for it in an start-up form (or "connect" pop-up form) with the required fields to fill in, etc. You can only establish the data-link if that step succeeds. So, once the data is collected, you create an object that handles the connection to the server and buffers the data.

Now, once this data-streamer exists, then it becomes possible to create a Viewer and/or Controller for the data. Because they need the data-streamer, they should simply take the data-streamer object by reference in their constructor. Of course, you need to control when these forms are created, but that's a given.

In all this, ownership is clear: the main() function creates and owns the data-streamer; the Viewer-Controller refer to the data-streamer which is required for them to exist.

So, the overall architecture, in ascii-art could look like:

Data-server (external component)
                  |
          Connection Manager
                  |
            Data Buffer (with periodic re-synchronization)
                  |
            Data Streamer (serves the data to the application)
              |       |            |
       Controller    Viewer   .. Viewer2 ... (any number of viewer

None of the above needs to or should be global, because they are all created in sequence based on what is necessary from them to exist (i.e. the Viewer-Controllers make no sense when there is no data-streamer yet, and so on for everything else). The job of the "main()" function is to perform this sequence of creation (and automatically guaranteeing the proper sequence of destruction through the RAII idiom) and then let all the things run for as long as there are no "quit" signal.

Of course, the above is a bit simplified because I haven't mentioned some of the important details that could affect the architecture (like thread synchronization mechanisms, dealing with connection problems, and how to properly buffer the data, etc.), but this would just be too long delve into.

Thank you for the explanation.

Does it mean that all the variables, classes and functions are members of "main".
So, if i want to access the the variables from other thread or form, I should use "main->StringVariable"?

If lets say I start a thread in "main" and I want to access "main->StringVariable" from that thread, I can't directly use "main->StringVariable" in that thread right because "main" is not a member of that thread.
Then, how should I do it?

In the pass, I just use global variables so that I can access the variables from everywhere, but obviously that is not the correct wsy.

Please advice.
Thanks.

>>Does it mean that all the variables, classes and functions are members of "main".

Only variables. So, yes, in principle, if you don't have any global data, then everything (all objects, but not classes or functions) is somehow under the scope of the main() function. But that's just because the main() function is the program.

>>So, if i want to access the the variables from other thread or form, I should use "main->StringVariable"?

No. main() is a function like any other, you cannot, from outside, access its local variables, because that simply cannot make any sense, and the compiler won't allow it, of course. You cannot access the variables of main. If you want an object that you create to have access to a variable of the main-function then you need to give it access to that variable by providing it with a pointer or reference to that variable.


>>If lets say I start a thread in "main" and I want to access "main->StringVariable" from that thread, I can't directly use "main->StringVariable" in that thread right because "main" is not a member of that thread.
>>Then, how should I do it?

You can't and you shouldn't. When you say "I start a thread in main and I want to access main->StringVariable", that's where things go wrong. You cannot make such a grave decision so casually, that's my main point. Especially in a multi-threaded environment. In this specific case, either StringVariable shouldn't be part of main() but a member of the object that uses it, or it provided by reference to the object that uses it, or the object shouldn't need to use it at all.

Each thread and/or each object should have its own well-defined task to accomplish and that task should have clear boundaries (what it should and should not do). Then, the data that it needs access to is a directly consequence of the task that it has to do, and usually, the collection of data elements it needs access to should be fairly small and closely related to each other (if not, you have a monolithic class or component, which is very bad).

The whole point of not having global variables is that, given a well-defined task for an object, it will have a small set of required data (both configurations and access to other components), and it is thus easy to provide it only with the data it needs and not give it access to anything else (since nothing is global). This way, you make sure that all the effects of the object or thread performing its task are restricted to the set of data that it has access to (i.e. local effects only). This is a lot easier to manage, to debug, and to maintain, while being faster, safer and less interdependent (i.e. more parallel, modular and flexible).

Once you have a well-define task for an object, and its set of required access to application data, then if you are asking "how do you provide that access?". The answer: by setting data-members of the object to be or refer to the data that it needs, usually, you can just do this all at once with the constructor (and that is generally easier and preferable).

For instance, with the architecture I proposed in my previous post, the main() function would look like:

int main() {
  
  //somehow collect configuration information.

  // Establish the connection by construction of a connection-manager object:
  ConnectionManager myConnection( /* pass config info here */ );

  // Create a data-streamer that will use the given server-connection:
  DataStreamer myStream( myConnection );

  // Create Viewers and Controllers by giving them the data-streamer by reference:
  ListViewer myListView( myStream );
  CommandLineEditor myCmdEditor( myStream );
  //... 

  // Run the application:
  while ( NoQuitSignal() ) { };

  return 0;  // all objects will be destroyed in correct order.
};

(of course, in reality you would do more in the main, the above is just for illustration)

The main point in the above is that each thing that you create should require access only to a few object that exist already, and so, it is easy to simply provide them upon construction (in more complex problems you might need post-construction initialization). If you properly group everything is sensible objects with clear responsibilities and data that they hold, then you shouldn't need more than what the above code-snippet illustrates. If you really have a number of data elements that are hard to classify under one object or another, and that almost everything needs access to it, then regroup all those unclassifiable elements into one class and make that class a Singleton class or a Fly-weight class (which you pass by reference to each object you create), but, in general, all that data should be essentially read-only data (and you have to worry about protecting the data against competing threads using mutexes and other synchronization tools).

Thank you very much for the detailed explanation.
Really appreciate it.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.