|
Thanks for the clarification. I've always been starting a BackgroundWorker from the GUI thread anyway, so I haven't actually tested which thread the WorkerComplete event ran on. Good to know.
Dybs
|
|
|
|
|
Looks like I started a big thread discussion with that question!
I actually ended up using the BackgroundWorker class to solve my problem; however I'm having a slight problem with it. My WorkerComplete event is not always being called from the main GUI thread. I have 4 threads now which use a base class to handle the management of a BackgroundWorker object and then override functions for DoWork and WorkerComplete. In 2 cases the WorkerComplete call comes from the main GUI thread and in the other 2 cases it comes from a completely different worker thread. I'm a bit confused by this as the same code is used to create and start the BackgroundWorker in all 4 cases.
Does anybody have any ideas as to what might cause the WorkerComplete event to be called from a worker thread and not the main GUI thread?
|
|
|
|
|
LetsMond wrote: My WorkerComplete event is not always being called from the main GUI thread
I doubt that very much. what makes you think so?
I suggest you check by logging the value of Thread.CurrentThread.ManagedThreadId
Luc Pattyn
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
I'm looking in the "Threads" Window to see which thread I'm on when I hit a breakpoint in the RunWorkerCompleted function. In the 2 bad cases I can see that it's not on the main thread (which is helpfully shown in green). Also if I then go on to try and perform a GUI operation things go horribly wrong.
|
|
|
|
|
Hi,
I ran some tests and there seems to be something wrong with BackgroundWorkers.
Contrary to what the documentation says, it seems like the (ProgressChanged and) RunWorkerCompleted event only executes on the GUI thread if the BGW was created (or got started?) on the GUI thread.
My investigation continues...
Luc Pattyn
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
Thanks for investigating!
I've been looking into the issue and I think I've found the problem, if not a good solution. When the BackgroundWorker doesn't work correctly I have created, displayed and closed a Form before starting the thread. The From changes the current SynchronizationContext object to its own thread. This becomes invalid after the Form closes (it doesn’t change it back to the original SynchronizationContext) and causes the strange behaviour when the BackgroundWorker is used.
The reason I'm seeing this might be because (for various unchangeable reasons) my program is an MFC App which also uses CLI.
I have no idea how to solve the problem. Yet
|
|
|
|
|
Hi,
seems my previous post, which was based on theory (documentation) and limited experience (only created and started on GUI), isn't correct; the BGW does not fire its progress/done events on the GUI event when it wasn't created/started on the GUI thread. I'll investigate further.
Luc Pattyn
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
Hi there,
In my project I'm creating a Bitmap from a char-ptr (as Scan0 IntPtr).
Now the bitmap (->the char ptr) gets a changed size as a single region of the image
ist cut out. If the stride is not a multiple of four, the createbitmap function causes
an exception! Now what can I do? I have no possiblity to change the incoming char-ptr
(because I get it sent on my interface).
If I calculate the next %4 stride value and use it, my bitmap isn't displayed correctly.
BTW: It's a monochrome image with a manually assigned MonoPalette, 1 BytePerPixel: Format8bppIndexed
Thanks for always helping me so much! Special thanks to NAVANEETH!
************************************************
A little side question:
From time to time my windows forms application is hanging in a strange way. I make a snapshot of a bitmap
and display it in one of the two picture boxes. Now when I drag my mouse down on the forms, i. e. to maximize/minimize
the form, there is no reaction and the application "hangs".
My app is not run as an exe, it's loaded as a DLL from a superior application.
It also occurs, that I am in the "main app" to calculate the image, then call the forms DLL to display it, but I do not
get the "forms application" (although it is loaded) popped up from the task bar. Usually I have to click on the "forms app"
in the taskbar -> then send an image from the main app -> and then the forms project gets popped up (you see, by aiming to
popping it up before). But that is crap and shouldn't behave that way!
modified on Friday, September 11, 2009 8:39 AM
|
|
|
|
|
cherrymotion wrote: I have no possiblity to change the incoming char-ptr
(because I get it sent on my interface).
Then you need to copy the pixel data to a properly row-aligned array.
You could use the Bitmap(Int32, Int32, PixelFormat) constructor and
copy the incoming data row-by-row to the new bitmap's data.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Hi,
I'm a newbie to VC++ using Visual Studio 2005 and facing the below mentioned problem
Read many articles over the internet but of less help.
Thing is i am stuck at using managed and managed functions at a time.
Have pasted the .lib code and application which demonstates the issue
.lib code:
int unmngd_sample(void)
{
return 1;
}
application code:
#pragma once
#include"unmngd.h"
namespace mngd {
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;
}
}
protected:
public: static System::Windows::Forms::RichTextBox^ Console;
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->Console = (gcnew System::Windows::Forms::RichTextBox());
this->SuspendLayout();
//
// Console
//
this->Console->Anchor = static_cast<System::Windows::Forms::AnchorStyles>((((System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Bottom)
| System::Windows::Forms::AnchorStyles::Left)
| System::Windows::Forms::AnchorStyles::Right));
this->Console->Enabled = false;
this->Console->Location = System::Drawing::Point(0, 24);
this->Console->Name = L"Console";
this->Console->Size = System::Drawing::Size(788, 556);
this->Console->TabIndex = 2;
this->Console->Text = L"";
//
// Form1
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(292, 262);
this->Controls->Add(this->Console);
this->Name = L"Form1";
this->Text = L"Form1";
this->ResumeLayout(false);
this->PerformLayout();
}
#pragma endregion
int func2(void)
{
return unmngd_sample();
}
};
int func1(const char *p, ...)
{
Form1::Console->AppendText("A");
return 1;
}
}
I've got a library unmngd.lib (unmanaged function), which is included in the GUI based application (managed func).
Enclosed unmngd.lib is unmanaged function and mixing is the application using managed functions.
Problem im facing is
1> if project->properties->
configuration properties->general->"Common Language Runtime support" is set to clr,
managed type or func cannot be used in an unmanaged func1(in form1.h").
Error: 'mngd::Form1': managed type or function cannot be used in an unmanaged function
2> if project->properties->configuration properties->general->"Common Language Runtime support" is set to clr/pure,
im not able to call unmanaged code(from .lib) in func2 (managed func).
Pls throw some light on this
|
|
|
|
|
You are getting this error because of the variable argument method. You can't have managed automatic variables inside a method that takes variable arguments. In your code I don't see any reason for using it. Try removing it
int func1(const char *p)
{
Form1::Console->AppendText("A");
return 1;
} There are potential problems with your code.
- Exposing a private variable violates OO rules. You should not expose the variable
console to outside. static keyword has a different implementation in managed world and it is not like the native implementation. In .NET, static variables will not be collected and will live until the application domain unloads.- Using
Form1::Console is dangerous. When Form1 is never instantiated before this call, you will run into troubles. As a solution, avoid using static members. Create a public method on Form1 which takes a string and call console->AppendText . Use this from func1 . func1 should get an instance of Form1 to do this.
Where are you calling func1 ?
|
|
|
|
|
Hey Navaneeth,
Let me brief you the situation. I've got a static lib file which is a win32 based and which requires application to register its display function address with the lib.
Library has few functions which keeps displaying the intermediate status of the functions called and hence the variable argument function required.
Earlier this library was used by the commandline application. Now I need to develop a GUI based application using the same lib. That is why i define variable argument function and register it with the library. This variable argument function which receives the messages from library, displays it on the Console.
Thanks a lot.
modified on Wednesday, September 9, 2009 2:01 AM
|
|
|
|
|
santoshkaif wrote: This variable argument function which receives the messages from library, displays it on the Console.
What will be the value of arguement p in your function int func1(const char *p, ...) ? Will that be some identifier to identify the types of variable arguements? If yes a possible solution is to write several method overloads that takes all possible types you are expecting. Depending on the type, you need call each overload. Also the way you implemented writing to rich text box is bad because of the reasons mentioned in my last post. Following is an improved version of your Form1 code.
public ref class Form1 : public System::Windows::Forms::Form
{
public:
static Form1^ GetInstance()
{
if(instance == nullptr)
instance = gcnew Form1();
return instance;
}
void PrintValue(System::Object value)
{
Console->AppendText(value.ToString());
}
private:
static Form1^ instance = nullptr;
System::Windows::Forms::RichTextBox^ Console;
} I have changed the Console variable to private and added a static variable named instance . This variable can be accessed using GetInstance method.
Following overloaded free functions are also added.
void WriteToScreen(int value)
{
Form1^ form = Form1::GetInstance();
form->PrintValue(value);
}
void WriteToScreen(double value)
{
Form1^ form = Form1::GetInstance();
form->PrintValue(value);
} Consider the following implementation of func1 . I am assuming in a call like func1("id", 10, 10.50) first argument will be int and second will be double.
void func1(const char* p,...)
{
va_list variable_arguements;
const char *temp;
va_start(variable_arguements, p);
int iValue;
double dValue;
for (temp = p; *temp; temp++)
{
switch (*temp)
{
case 'i':
iValue = va_arg(variable_arguements, int);
WriteToScreen(iValue);
break;
case 'd':
dValue = va_arg(variable_arguements, double);
WriteToScreen(dValue);
break;
default:
break;
}
}
va_end(variable_arguements);
} Finally, You need to modify your main method to use the singleton instance.
int main(array<System::String ^> ^args)
{
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
Form1^ frm = Form1::GetInstance();
Application::Run(frm);
return 0;
} Hope that helps
|
|
|
|
|
Thanks, for a newbie this is a help to greater extent.
One more thing imp is I'm using visual studio 2005.
>> What will be the value of arguement p in your function int func1(const char *p, ...)?
Value of argument p in function int func1(const char *p, ...) can be anything. Its as good as printf(). I've built the sample library and application project and is as below
library.h
--------------------
#ifndef _LIBRARY_H_
#define _LIBRARY_H_
void register_func(int(*pConsoleHandle)(const char* p, ...));
void library_message1(void);
void library_message2(void);
void library_message3(void);
void library_operation(void);
#endif //_LIBRARY_H_
library.c
-----------------------
#include"library.h"
int(*pFuncHandle)(const char* p, ...);
void register_func(int(*pConsoleHandle)(const char* p, ...))
{
pFuncHandle = pConsoleHandle;
}
void library_message1(void)
{
pFuncHandle("Library msg1 is up!!");
}
void library_message2(void)
{
char msg[] = "Library msg2";
pFuncHandle("Library is up!!");
}
void library_message3(void)
{
int i = 3;
pFuncHandle("Library msg%d is up!!",i);
}
void library_operation(void)
{
library_message1();
library_message2();
library_message3();
}
this code generates library.lib which is to be included in GUI application.
GUI_Application:
-----------------------
#pragma once
#include <stdio.h>
#include <stdarg.h>
#include "library.h"
namespace GUI_APP {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
int DisplayMessage(const char* msg, ...);
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
register_func(DisplayMessage);
}
protected:
~Form1()
{
if (components)
{
delete components;
}
}
public: static System::Windows::Forms::RichTextBox^ Console;
protected:
private:
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
void InitializeComponent(void)
{
this->Console = (gcnew System::Windows::Forms::RichTextBox());
this->SuspendLayout();
this->Console->Location = System::Drawing::Point(-2, -2);
this->Console->Name = L"richTextBox1";
this->Console->Size = System::Drawing::Size(296, 265);
this->Console->TabIndex = 0;
this->Console->Text = L"";
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(292, 262);
this->Controls->Add(this->Console);
this->Name = L"Form1";
this->Text = L"Form1";
this->ResumeLayout(false);
}
#pragma endregion
void library_func(void)
{
library_operation();
}
};
int DisplayMessage(const char* msg, ...)
{
int ret = 0;
va_list ap;
char *pBuffer = new char[256];
va_start(ap, msg);
ret = vsprintf(pBuffer, msg, ap);
GUI_APP::Form1::Console->AppendText(gcnew System::String((const char*)msg));
delete(pBuffer);
va_end(ap);
return (ret);
}
}
This GUI_application is where i'm unable to call and use unmanaged functions.
Thanks in advance
modified on Wednesday, September 9, 2009 2:52 PM
|
|
|
|
|
Well in that case we can make use of std::stringstream and have only one overload. You need to modify the PrintValue method in your form to take a managed string rather than System::Object .
void PrintValue(String^ value)
{
Console->AppendText(value);
} WriteToScreen method now requires only one overload which takes a std::stringstream& .
void WriteToScreen(std::stringstream& value)
{
std::string str = stream.str();
String^ managedString = gcnew String(str.c_str());
Form1^ form = Form1::GetInstance();
form->PrintValue(managedString);
} func1 is also modified to behave like printf .
void func1(const char* p,...)
{
const char *temp; int iValue; double dValue; bool percentageFound = false;
va_list variable_arguements;
va_start(variable_arguements, p);
std::stringstream stream;
for (temp = p; *temp; temp++)
{
if(*temp != '%' && !percentageFound)
stream << *temp;
else if(!percentageFound)
{
percentageFound = true;
continue;
}
if(percentageFound)
{
switch (*temp)
{
case 'd':
iValue = va_arg(variable_arguements, int);
stream << iValue;
break;
default:
break;
}
percentageFound = false;
}
}
va_end(variable_arguements);
WriteToScreen(stream);
} I have added only for %d and you can add cases for all other types. A function call like func1("Twelve = %d and Ten = %d",12,10); will print Twelve = 12 and Ten = 10 .
Hope this helps.
|
|
|
|
|
But i get compilation errors as
error C2065: 'stream' : undeclared identifier
error C2228: left of '.str' must have class/struct/union type is ''unknown-type''
Error occurs at
void WriteToScreen(std::stringstream& value){
std::string str = stream.str(); <---------------------Error
String^ managedString = gcnew String(str.c_str());
Form1^ form = Form1::GetInstance();
form->PrintValue(managedString);
}
Just for compilation purpose, if i make the following modification
std::string str;
I start getting following linker errors
Compiling managed resources...
Read in 0 resources from "f:\Projects\Temp\MTK3\GUI\GUI_APP\GUI_APP\GUI_APP\Form1.resx"
Writing resource file... Done.
Compiling resources...
Linking...
Form1.obj : error LNK2028: unresolved token (0A00001F) "void __clrcall register_func(int (__clrcall*)(char const *,...))" (?register_func@@$$FYMXP6MHPBDZZ@Z) referenced in function "public: __clrcall GUI_APP::Form1::Form1(void)" (??0Form1@GUI_APP@@$$FQ$AAM@XZ)
GUI_APP.obj : error LNK2028: unresolved token (0A000016) "void __clrcall library_operation(void)" (?library_operation@@$$FYMXXZ) referenced in function "private: void __clrcall GUI_APP::Form1::library_func(void)" (?library_func@Form1@GUI_APP@@$$FA$AAMXXZ)
Form1.obj : error LNK2028: unresolved token (0A000022) "void __clrcall library_operation(void)" (?library_operation@@$$FYMXXZ) referenced in function "private: void __clrcall GUI_APP::Form1::library_func(void)" (?library_func@Form1@GUI_APP@@$$FA$AAMXXZ)
Form1.obj : error LNK2019: unresolved external symbol "void __clrcall library_operation(void)" (?library_operation@@$$FYMXXZ) referenced in function "private: void __clrcall GUI_APP::Form1::library_func(void)" (?library_func@Form1@GUI_APP@@$$FA$AAMXXZ)
GUI_APP.obj : error LNK2001: unresolved external symbol "void __clrcall library_operation(void)" (?library_operation@@$$FYMXXZ)
Form1.obj : error LNK2019: unresolved external symbol "void __clrcall register_func(int (__clrcall*)(char const *,...))" (?register_func@@$$FYMXP6MHPBDZZ@Z) referenced in function "public: __clrcall GUI_APP::Form1::Form1(void)" (??0Form1@GUI_APP@@$$FQ$AAM@XZ)
fatal error LNK1120: 5 unresolved externals
GUI_APP - 7 error(s), 1 warning(s)
|
|
|
|
|
Common language runtime support is set to /clr:pure.
To call the library functions "register_func" or "library_operation" from the static library.lib, if
Common language runtime support is set to (/clr) then the errors thrown are
error C3269: 'GUI_APP::Form1::DisplayMessage' : a member-function of a managed type cannot be declared with '...'
Form1.cpp
error C3269: 'GUI_APP::Form1::DisplayMessage' : a member-function of a managed type cannot be declared with '...'
error C3269: 'GUI_APP::Form1::DisplayMessage' : a member-function of a managed type cannot be declared with '...'
error C3821: 'GUI_APP::Form1::WriteToScreen': managed type or function cannot be used in an unmanaged function
error C3642: 'void GUI_APP::Form1::WriteToScreen(std::stringstream &)' : cannot call a function with __clrcall calling convention from native code
error C3175: 'GUI_APP::Form1::WriteToScreen' : cannot call a method of a managed type from unmanaged function 'GUI_APP::Form1::DisplayMessage'
note: 'int GUI_APP::Form1::DisplayMessage(const char *,...)': to compile this varargs function as managed code, use /clr:pure
Form1.h(76) : see declaration of 'GUI_APP::Form1::DisplayMessage'
warning C4793: 'vararg' : causes native code generation for function 'int GUI_APP::Form1::DisplayMessage(const char *,...)'
Form1.h(76) : see declaration of 'GUI_APP::Form1::DisplayMessage'
error C3645: 'GUI_APP::Form1::DisplayMessage' : __clrcall cannot be used on functions compiled to native code
GUI_APP - 7 error(s), 1 warning(s)
|
|
|
|
|
The code which I provided compiles fine on my machine. Have you included proper header files? Have you used proper namespaces? Also use /clr compiler switch rather than /clr:pure .
|
|
|
|
|
Yeah, Common language runtime support is set to "clr" only.
Enclosing code just in case to verify if am doing anything wrong
#pragma once
#include <iostream>
#include <stdio.h>
#include <stdarg.h>
#include <sstream>
#include <iostream>
#include <string>
#pragma managed(push, off)
extern "C"{
#include "library.h"
};
#pragma managed(pop)
namespace GUI_APP {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace std;
int DisplayMessage(const char* p,...);
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
register_func(DisplayMessage);
}
static Form1^ GetInstance()
{
if(instance == nullptr)
instance = gcnew Form1();
return instance;
}
void PrintValue(String^ value)
{
Console->AppendText(value);
}
private:
static Form1^ instance = nullptr;
System::Windows::Forms::RichTextBox^ Console;
protected:
~Form1()
{
if (components)
{
delete components;
}
}
protected:
private:
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
void InitializeComponent(void)
{
this->Console = (gcnew System::Windows::Forms::RichTextBox());
this->SuspendLayout();
this->Console->Location = System::Drawing::Point(-2, -2);
this->Console->Name = L"richTextBox1";
this->Console->Size = System::Drawing::Size(296, 265);
this->Console->TabIndex = 0;
this->Console->Text = L"";
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(292, 262);
this->Controls->Add(this->Console);
this->Name = L"Form1";
this->Text = L"Form1";
this->ResumeLayout(false);
}
#pragma endregion
void library_func(void)
{
library_operation();
}
void WriteToScreen(std::stringstream& value)
{
std::string str = stream.str();
String^ managedString = gcnew String(str.c_str());
Form1^ form = Form1::GetInstance();
form->PrintValue(managedString);
}
};
int DisplayMessage(const char* p,...)
{
const char *temp; int iValue; double dValue; bool percentageFound = false;
va_list variable_arguements;
va_start(variable_arguements, p);
int DisplayedCharCount = 0;
std::stringstream stream;
for (temp = p; *temp; temp++)
{
DisplayedCharCount++;
if(*temp != '%' && !percentageFound)
stream << *temp;
else if(!percentageFound)
{
percentageFound = true;
continue;
}
if(percentageFound)
{
switch (*temp)
{
case 'd':
iValue = va_arg(variable_arguements, int);
stream << iValue;
break;
default:
break;
}
percentageFound = false;
}
}
va_end(variable_arguements);
WriteToScreen(stream);
return DisplayedCharCount;
}
}
following are the error messages
error C2065: 'stream' : undeclared identifier
error C2228: left of '.str' must have class/struct/union
type is ''unknown-type''
error C3861: 'WriteToScreen': identifier not found
warning C4793: 'vararg' : causes native code generation for function 'int GUI_APP::DisplayMessage(const char *,...)'
see declaration of 'GUI_APP::DisplayMessage'
pls let me know where i am going wrong?
if i make "DisplayMessage" as member function of "Form1" class, then below error is thrown
'GUI_APP::Form1::DisplayMessage' : a member-function of a managed type cannot be declared with '...'
modified on Thursday, September 10, 2009 1:57 PM
|
|
|
|
|
WriteToScreen should be a free-function not a member of Form1 . Take that function from class and put it on top of DisplayMessage .
|
|
|
|
|
Hey Navaneeth, Now it works. Tons of Thanks to u, u've done wonders for me!!
|
|
|
|
|
I need your expert advice again.
This is in continuation with the earlier code. If "DisplayMessage" function is registered with library function and if one of the lib functions(which would have lots of display messages) is called from this application, console(i.e. richtextbox) gives the impression to the user that its hanged. Once the control is returned back to application(from the lib function), all the messages get displayed on console at once.
I want to know how to get the lib messages displayed on console as and when lib func does it, instead of displaying all the messages at once(which also gives the impression to the user its hung).
|
|
|
|
|
In such case, use a separate thread to handle the messages. To access rich text box from worker thread, you need to use Invoke /BeginInvoke to avoid cross-thread exceptions. This[^] post may help you.
|
|
|
|
|
I use this sort of code in a program i'm making at the moment:
if (loginForm == nullptr) {
loginForm = gcnew Login;
loginForm->Show();
} else {
loginForm->Activate();
}
I'm wondering how do i get the Login form to call methods from the initial (parent) form?
I include the login form in this form and set loginForm to nullptr when the form runs. The second form loads, but i can't work out how to call a method from the parent. Any ideas?
|
|
|
|
|
rtshield wrote: I'm wondering how do i get the Login form to call methods from the initial (parent) form?
You can make the methods public and when login form is instantiated, pass the parent forms instance to login form via constructor.
if (loginForm == nullptr) {
loginForm = gcnew Login(this);
loginForm->Show();
} else {
loginForm->Activate();
} Login forms constructor should also be modified to accept a parent forms object.
ref class ParentForm;
ref class LoginForm : public Form
{
private:
ParentForm^ parentForm = nullptr;
public:
LoginForm(ParentForm^ p)
: parentForm(p)
{
}
} You need to forward declare parent form in the header file and include parentform.h in your CPP file to avoid circular dependencies.
|
|
|
|