Page 1 of 2

using wxWidgets in library

Posted: Mon Mar 04, 2019 12:02 pm
by ppsmurf
Hello,
I'm currently writting a multiplatorm library to work with smartcards. The library itself does not have any main window, it just implements some "computing" functions. But in some situations user interaction is required (e.g. confirm or enter pin). So I want use wxWidgets in a non global way (doing some operations completly unrelated to GUI, show window then continue).

This is my GUI class. IMPLEMENT_APP_NO_MAIN is used. InitializeGUI is called in initialization of my own lib.

Code: Select all

class MyGUI: public wxApp {
public:
	MyGUI() {};
	virtual ~MyGUI(){
		wxUninitialize();
	};
	
	static void InitializeGUI() {
		wxApp::SetInstance(wxCreateApp());
		wxGetApp().OnInit();
	};

	virtual bool OnInit(){
		if(!wxInitialize())
			throw ..;
	
		m_isInit = true;
		return m_isInit;
	};
	
	void CreateSignConfirmFrame(){
		SignConfirm *confirm = new SignConfirm(...);	// wxFrame
		confirm->Show(true);
		wxGetApp().OnRun();
	};
	
	bool ExportPrivateKeyMsgBox(const std::string& keyName) {
		std::string capt = "Export";
		std::string msg = "Really export %s?";
		return wxMessageBox(wxString::Format(msg.c_str(), keyName.c_str()), capt.c_str(),
						wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION, NULL) == wxYES;
	};
	
	..
	..some other CreateFrame functions..
	..
};

wxDECLARE_APP(MyGUI);
This works well if only one CreateFrame function is called at a time (this is ok for me right now, but it may be problem in the future). So my questions are:
1) Is there a "correct" way of doing this, without some complex GUI control? I really just want have a few methods to show a certain window.
2) I need show one window in non-blocking way (just window with some text in it). Basically show window with some info for user and continue in program execution with this window still shown. I tried create this window in second thread, but got assertion faild: "assert 'wxThread::IsMain()' failed in wxMutexGuiLeaveOrEnter()". So I really don't know how to achive this.

Code: Select all

m_thread = new std::thread([]() {
	m_dialog = new PinPadDialog();	// wxDialog
	m_dialog->ShowModal();
});
I'm new to wxWidgets and generally in GUI development, so any help is appreciated.
Thank you.

Re: using wxWidgets in library

Posted: Mon Mar 04, 2019 1:11 pm
by PB
Did you check the DLL (Windows only) sample bundled with wxWidgets? If not, perhaps it (including its readme.txt) can give some hints.

I never used it but perhaps you could also take a look at approach described here
https://simon.rozman.si/computers/wxwid ... dll-plugin

Generally, you cannot use any wxWidgets GUI classes in a secondary thread, where the definition of primary thread is "thread which run wxApp::OnInit()".

BTW, any wxFrame (or any top-level non-modal window) is a non-blocking window. But from the user-point-of-view it may look odd of some window without an obvious relationship to a running application pops out of nowhere...

Re: using wxWidgets in library

Posted: Mon Mar 04, 2019 1:41 pm
by ppsmurf
Thank you for your reply. Yes I check the DLL sample, but I dont think this is what i want.
wxFrame is non-blocking, but in context of my lib is blocking because it waits in main loop i guess:

Code: Select all

PinPadDialog* pinpad= new PinPadDialog(...);	// wxFrame
pinpad->Show(true);
wxGetApp().OnRun();	// program execution waits here, until frame is closed
I have no "global" main loop, every window start its own main loop as shown in code before.

Re: using wxWidgets in library

Posted: Mon Mar 04, 2019 3:18 pm
by ONEEYEMAN
Hi,
ppsmurf wrote: Mon Mar 04, 2019 12:02 pm Hello,
I'm currently writting a multiplatorm library to work with smartcards. The library itself does not have any main window, it just implements some "computing" functions. But in some situations user interaction is required (e.g. confirm or enter pin). So I want use wxWidgets in a non global way (doing some operations completly unrelated to GUI, show window then continue).

This is my GUI class. IMPLEMENT_APP_NO_MAIN is used. InitializeGUI is called in initialization of my own lib.

Code: Select all

class MyGUI: public wxApp {
public:
	MyGUI() {};
	virtual ~MyGUI(){
		wxUninitialize();
	};
	
	static void InitializeGUI() {
		wxApp::SetInstance(wxCreateApp());
		wxGetApp().OnInit();
	};

	virtual bool OnInit(){
		if(!wxInitialize())
			throw ..;
	
		m_isInit = true;
		return m_isInit;
	};
	
	void CreateSignConfirmFrame(){
		SignConfirm *confirm = new SignConfirm(...);	// wxFrame
		confirm->Show(true);
		wxGetApp().OnRun();
	};
	
	bool ExportPrivateKeyMsgBox(const std::string& keyName) {
		std::string capt = "Export";
		std::string msg = "Really export %s?";
		return wxMessageBox(wxString::Format(msg.c_str(), keyName.c_str()), capt.c_str(),
						wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION, NULL) == wxYES;
	};
	
	..
	..some other CreateFrame functions..
	..
};

wxDECLARE_APP(MyGUI);
This works well if only one CreateFrame function is called at a time (this is ok for me right now, but it may be problem in the future). So my questions are:
1) Is there a "correct" way of doing this, without some complex GUI control? I really just want have a few methods to show a certain window.
What do you mean by saying "one CreateFrame function is called at a time"? Remember - no GUI should be created/accessed in the secondary thread. Or you mean you want/need to execute the function twice? What problem did you encounter?
ppsmurf wrote: Mon Mar 04, 2019 12:02 pm 2) I need show one window in non-blocking way (just window with some text in it). Basically show window with some info for user and continue in program execution with this window still shown. I tried create this window in second thread, but got assertion faild: "assert 'wxThread::IsMain()' failed in wxMutexGuiLeaveOrEnter()". So I really don't know how to achive this.
Are you looking for a non-modal dialog, maybe?

Thank you.

Re: using wxWidgets in library

Posted: Mon Mar 11, 2019 12:19 pm
by ppsmurf
ONEEYEMAN wrote: Mon Mar 04, 2019 3:18 pm What do you mean by saying "one CreateFrame function is called at a time"? Remember - no GUI should be created/accessed in the secondary thread. Or you mean you want/need to execute the function twice? What problem did you encounter?
Sometimes (not very often) library requiers some user confirmation. So I call this function for example:

Code: Select all

void CreateSignConfirmFrame(){
	SignConfirm *confirm = new SignConfirm(...);	// wxFrame
	confirm->Show(true);
	wxGetApp().OnRun();
};
This works fine, but my question is: Is this the right approach?
ONEEYEMAN wrote: Mon Mar 04, 2019 3:18 pm Are you looking for a non-modal dialog, maybe?
And secondly, this works fine unless non-blocking dialog is needed. If I call "CreateSignConfirmFrame()" it is "stuck" in onRun loop until window is closed (so from my point of view this is blocking).

Edit:
I tried using wxWidgets in second thread (initialized and run all UI operations here), this works fine, but I have problem in MacOS. Aperently in MacOS Cocoa UI have to run in main thread, so a get:

Code: Select all

Assertion failure in +[NSUndoManager _endTopLevelGroupings].....
Any idea how to hack this?

Thank you.

Re: using wxWidgets in library

Posted: Mon Mar 11, 2019 2:31 pm
by ONEEYEMAN
Hi,
ppsmurf wrote: Mon Mar 11, 2019 12:19 pm
ONEEYEMAN wrote: Mon Mar 04, 2019 3:18 pm What do you mean by saying "one CreateFrame function is called at a time"? Remember - no GUI should be created/accessed in the secondary thread. Or you mean you want/need to execute the function twice? What problem did you encounter?
Sometimes (not very often) library requiers some user confirmation. So I call this function for example:

Code: Select all

void CreateSignConfirmFrame(){
	SignConfirm *confirm = new SignConfirm(...);	// wxFrame
	confirm->Show(true);
	wxGetApp().OnRun();
};
This works fine, but my question is: Is this the right approach?
What is the type of "SignConfirm" object?
ppsmurf wrote: Mon Mar 11, 2019 12:19 pm
ONEEYEMAN wrote: Mon Mar 04, 2019 3:18 pm Are you looking for a non-modal dialog, maybe?
And secondly, this works fine unless non-blocking dialog is needed. If I call "CreateSignConfirmFrame()" it is "stuck" in onRun loop until window is closed (so from my point of view this is blocking).
Why do you need to call "wxGetApp.OnRun()"?

I think you design has a big flaw here.
Please explain what needs to be done in plain English and we will try to help.
ppsmurf wrote: Mon Mar 11, 2019 12:19 pm Edit:
I tried using wxWidgets in second thread (initialized and run all UI operations here), this works fine, but I have problem in MacOS. Aperently in MacOS Cocoa UI have to run in main thread, so a get:

Code: Select all

Assertion failure in +[NSUndoManager _endTopLevelGroupings].....
Any idea how to hack this?

Thank you.
This can't be hacked. It never will work.
One more time (also see above):

GUI DOES NOT WORK IN THE SECONDARY THREADS!!!!!! EVER!!!!!

It may work in one platform, but even then there is no guarantee.

Therefore, in the cross-platform environment GUI works in the primary thread only (the one that starts the application) and only some long task are executed in the secondary thread, soi not to block GUI event loop.
Communication is done through the notification events/messages.

Re: using wxWidgets in library

Posted: Mon Mar 11, 2019 3:41 pm
by ppsmurf
Hi, sorry for my stupidity, I'm new in wxWidgets and GUI programming in general.
ONEEYEMAN wrote: Mon Mar 11, 2019 2:31 pm What is the type of "SignConfirm" object?
Why do you need to call "wxGetApp.OnRun()"?
SignConfirm is wxFrame. (Besides wxFrame I use some wxDialogs too.) I don't know how to explain it correctly, but my library is not "controled by GUI", so I can't start main GUI event loop. Because of that I call "wxGetApp.OnRun()" after "frame->show()".
I would like to use wxWidgets only to show a few separate windows (wxFrames or wxDialogs), without global main GUI event loop. So I came up with this code, but I feel it's somehow tricky :D and thats why I start this topic.

Code: Select all

void CreateSignConfirmFrame(){
	SignConfirm *confirm = new SignConfirm(...);	// wxFrame
	confirm->Show(true);
	wxGetApp().OnRun();
}
ONEEYEMAN wrote: Mon Mar 11, 2019 2:31 pm I think you design has a big flaw here.
Yes I thinks that too, but I don't know better solution. Well this design would be probably sufficient enough if I could achieve non-blocking dialog.

Do you understand my situation a little bit more? Also sorry for my bad english.
Thanks for your time!

Re: using wxWidgets in library

Posted: Mon Mar 11, 2019 3:58 pm
by ONEEYEMAN
Hi,
ppsmurf wrote: Mon Mar 11, 2019 3:41 pm Hi, sorry for my stupidity, I'm new in wxWidgets and GUI programming in general.
ONEEYEMAN wrote: Mon Mar 11, 2019 2:31 pm What is the type of "SignConfirm" object?
Why do you need to call "wxGetApp.OnRun()"?
SignConfirm is wxFrame. (Besides wxFrame I use some wxDialogs too.) I don't know how to explain it correctly, but my library is not "controled by GUI", so I can't start main GUI event loop. Because of that I call "wxGetApp.OnRun()" after "frame->show()".
I would like to use wxWidgets only to show a few separate windows (wxFrames or wxDialogs), without global main GUI event loop. So I came up with this code, but I feel it's somehow tricky :D and thats why I start this topic.

Code: Select all

void CreateSignConfirmFrame(){
	SignConfirm *confirm = new SignConfirm(...);	// wxFrame
	confirm->Show(true);
	wxGetApp().OnRun();
}
What do you mean by saying "my library is not controlled by GUI"? Are you trying to create some kind of a plug-in? Or you want to start the program from some console application?

As I said - it is better to explain your situation in plain English (what you want to achieve and how the program should work) so that we can better help you. As it stands right now, there are only bits and pieces. Put them all together for you is very difficult.
And don't worry about language - I'm also ESL person (as you could probably guess by my signature). So try to explain what you want to achieve and we will try to help.
ppsmurf wrote: Mon Mar 11, 2019 3:41 pm
ONEEYEMAN wrote: Mon Mar 11, 2019 2:31 pm I think you design has a big flaw here.
Yes I thinks that too, but I don't know better solution. Well this design would be probably sufficient enough if I could achieve non-blocking dialog.

Do you understand my situation a little bit more? Also sorry for my bad english.
Thanks for your time!
No, not really.
You should explain what you program should do, not how you envision it to work.
This will be better for especially since you are new to GUI programming in general.

Thank you.

Re: using wxWidgets in library

Posted: Tue Mar 12, 2019 9:41 am
by ppsmurf
Ok, I will try to explain what I'm trying to achieve.
I'm working on cross-platform dynamic library. Which has C and C++ interface (C interface is primarily used). The library implements "PKI" (public key infrastructure), basically it works with smartcards, generates private/public key pairs, parsing x509 certificates, creating PKCS10 requests and so on. So it's just set of functions (without dllmain). Some of these functions requiers interaction with user. For example before generating key pair, user needs to input PIN. If more than one smartcards are connected, user needs to select the one he wants to work with.

I implemented these dialogs in the way I described above ("dialog->ShowModal()" or "wxGetApp.OnRun()" after "frame->show()"). Main problem is with PinPad readers: https://www.floss-shop.de/media/image/2 ... 00x600.jpg.
Because I need to show window to user, with text: "Please insert your PIN on keyboard of the PinPad reader and press green button.", this window have to be on screen while user inputs the pin on the pinpad keyboard. So program "flow" needs to continue after:

Code: Select all

Pinpad* info = new Pinpad();
info->Show();
wxGetApp.OnRun();
.. with window still open.

Interface example (pseudo, just for demonstration):

Code: Select all

__declspec(dllexport) int Initialize(uint32_t initOptions){
	// initializing other libraries
	// loading some files
	// initializing wxWidgets
	return 0;
}

__declspec(dllexport) int Uninitialize(){ ... }

__declspec(dllexport) int GenerateKeyPair(uint32_t keySize, const char* keyName, uint32_t flags){ 
	..
	..
	// somewhere very deep in this function needs to be PIN or PinPad dialog
	std::string pin;
	if(reader->IsPinPad()){
		Pinpad* info = new Pinpad();	// wxDialog or wxFrame?
		info->Show();
		wxGetApp.OnRun();			// <- this can not work, because it waits here until the window is closed 
		
		// this function waits for user inputs pin on pinpad keyboard
		pin = reader->GetPinFromPinPad();
		// after user inputs pin, dialog should be closed
		info->Close();
		
	}else{
		PinDialog dialog = new PinDialog(); // wxDialog
		dialog->showModal();
	
		pin = dialog->GetPin();
	}
	
	// pin checks
	// continues with key generation..
	..
 }

I don't have access to the aplication where my library is used. For now it is console aplication, but I'm pretty sure one day someone will want using it in GUI aplication.

My questions are:
1) What is the correct and simplest way of using wxWidgets in my library?
2) How can be resolve the problem with pinPad dialog?

I hope I explained it in understandable way. Did my best :D.
Thank you, I appreciate your help.

Re: using wxWidgets in library

Posted: Tue Mar 12, 2019 2:59 pm
by ONEEYEMAN
Hi,
ppsmurf wrote: Tue Mar 12, 2019 9:41 am Ok, I will try to explain what I'm trying to achieve.
I'm working on cross-platform dynamic library. Which has C and C++ interface (C interface is primarily used). The library implements "PKI" (public key infrastructure), basically it works with smartcards, generates private/public key pairs, parsing x509 certificates, creating PKCS10 requests and so on. So it's just set of functions (without dllmain). Some of these functions requiers interaction with user. For example before generating key pair, user needs to input PIN. If more than one smartcards are connected, user needs to select the one he wants to work with.

I implemented these dialogs in the way I described above ("dialog->ShowModal()" or "wxGetApp.OnRun()" after "frame->show()"). Main problem is with PinPad readers: https://www.floss-shop.de/media/image/2 ... 00x600.jpg.
If they are dialogs, you should use dialogs.
And you don't need to use "wxGetApp.OnRun()".
You should just use either modal or modeless dialogs and that's it.
ppsmurf wrote: Tue Mar 12, 2019 9:41 am Because I need to show window to user, with text: "Please insert your PIN on keyboard of the PinPad reader and press green button.", this window have to be on screen while user inputs the pin on the pinpad keyboard. So program "flow" needs to continue after:

Code: Select all

Pinpad* info = new Pinpad();
info->Show();
wxGetApp.OnRun();
.. with window still open.
You problem is here - 1. you don't need "Pinpad" to be wxFrame, it needs to be wxDialog, and 2. you don't need to call "OnRun()" (even with the frame).
Don't know why you think you should - application is not finished.
Moreover - why do you need a modeless dialog here?
The flow should stop until the user either enters the pin and click OK or cancel the dialog. But that's besides the point.
ppsmurf wrote: Tue Mar 12, 2019 9:41 am Interface example (pseudo, just for demonstration):

Code: Select all

__declspec(dllexport) int Initialize(uint32_t initOptions){
	// initializing other libraries
	// loading some files
	// initializing wxWidgets
	return 0;
}

__declspec(dllexport) int Uninitialize(){ ... }

__declspec(dllexport) int GenerateKeyPair(uint32_t keySize, const char* keyName, uint32_t flags){ 
	..
	..
	// somewhere very deep in this function needs to be PIN or PinPad dialog
	std::string pin;
	if(reader->IsPinPad()){
		Pinpad* info = new Pinpad();	// wxDialog or wxFrame?
		info->Show();
		wxGetApp.OnRun();			// <- this can not work, because it waits here until the window is closed 
		
		// this function waits for user inputs pin on pinpad keyboard
		pin = reader->GetPinFromPinPad();
		// after user inputs pin, dialog should be closed
		info->Close();
		
	}else{
		PinDialog dialog = new PinDialog(); // wxDialog
		dialog->showModal();
	
		pin = dialog->GetPin();
	}
	
	// pin checks
	// continues with key generation..
	..
 }

Wait, what is the difference between those 2 scenarios - IsPinPad() == true and IsPinPad() == false?
Moreover you create the Pinpad object, never use it and never delete it. So, I'm curious - what is the purpose of it being there? You take input in "GetPinFromPinPad()" anyway...
But the main point is the question above.
ppsmurf wrote: Tue Mar 12, 2019 9:41 am I don't have access to the aplication where my library is used. For now it is console aplication, but I'm pretty sure one day someone will want using it in GUI aplication.

My questions are:
1) What is the correct and simplest way of using wxWidgets in my library?
2) How can be resolve the problem with pinPad dialog?

I hope I explained it in understandable way. Did my best :D.
Thank you, I appreciate your help.
I think I tried to answer those 2 questions above with some more questions. ;-)
Again the main point is - you don't need any frames. Everythig should be done in dialogs. There is even extra specialized dialogs for you - take a look here or here.
And you can build the dialogs sample and see how they look on the system.
And of course you don't need the branching - the code should be the same. It shuoldn't matter whether the PinPad is attached or the PIN is entered from the keyboard. Unless you justify it somehow.

Thank you.

Re: using wxWidgets in library

Posted: Tue Mar 12, 2019 3:52 pm
by ppsmurf
ONEEYEMAN wrote: Tue Mar 12, 2019 2:59 pm Wait, what is the difference between those 2 scenarios - IsPinPad() == true and IsPinPad() == false?
This is main problem. The diference is:
IsPinPad() == false
- user enters PIN in dialog on sreen (in GUI on PC :D),
- the flow should stop until the user either enters the pin and click OK

IsPinPad() == true
- user enters pin on Pinpad reader itself (viz. picture above) meanwhile on screen is shown just information for user: "Please enter PIN on keyboard of pinPad reader and press green button". So in PinPad situation, user enters pin on external device attached to the PC, but in same time the informative dialog needs to be on screen.
- the flow should contine and user enters the pin on external device, which "GetPinFromPinPad()" is for (but in same time dialog informs user, he needs to input pin on pinpad reader).


Do you understand the problem now? :)
Thank you again.

Re: using wxWidgets in library

Posted: Tue Mar 12, 2019 4:07 pm
by ONEEYEMAN
Hi,
Yes I do.
And as the user of such applications with 10 years, I can guarantee that those 2 situations are not different.
It doesn't matter what user will use - keyboard or PinPad. (S)he will see the dialog on the screen which will display the appropriate "*" symbols. And the program should stop until this PIN will be entered or the dialog canceled.

Why do you think I should continue operating the application without (valid) PIN?
If you can give me such scenario - then this dialog should be modeless.

But independently of that - why the library should care? Think of PinPad as the same external device as the keyboard. There is absolutely no difference between them.

More over - if you want it to work this way - you can hide the text control and the button(s) on the dialog and when the user press OK on the PinPad finish the dialog

The difference starts when you implements virtual keyboard (for touch screen) but that is different topic.

Thank you.

Re: using wxWidgets in library

Posted: Tue Mar 12, 2019 5:04 pm
by ppsmurf
ONEEYEMAN wrote: Tue Mar 12, 2019 4:07 pm But independently of that - why the library should care? Think of PinPad as the same external device as the keyboard. There is absolutely no difference between them.
From user point of view there is no difference, but from program view it is different (at least in my situation). I'm using library witch ensures layer bethween me an the reader. I have to imlement abstract class from library, this class has only two methods one for show dialog and other for hide dialog. After layer library calls my "Show()", does something like "GetPinFromPinPad()" and waits for input on pinpad reader, when user inputs pin, it calls "Hide()". So what is between "Show()" and "Hide()" is not in my direction, but I need the flow continue after "Show()", so layer library can call "GetPinFromPinPad()". With normal PIN it is almost same, but my "Show()" method returns inserted pin. (This is not problem.)

Example:

Code: Select all

class PinPadDialog : public PinPadAbstract{
public:
PinPadDialog() : m_info(nullptr){};
virtual void Show(){
	m_info = new Pinpad();	// wxDialog 
	m_info->Show();
} override;

virtual  void Hide(){
	m_info->Close();
} override;

private:
Pinpad* m_info;
}

Code: Select all

PinPadDialog dialog;
// reader is from "layer" library
auto reader = GetReader();
reader->SetPinPadDialog(&dialog);

// continues with key generation with reader context, to show() and hide() dialog
GenerateKeyPair(size, keyName, reader);

I can't post real code here, so this is just pseudo, but I hope you get the idea.
I guess bottom line of this is: I need show dialog and continues in program flow, while it's shown.

Thank you :).

Re: using wxWidgets in library

Posted: Tue Mar 12, 2019 5:15 pm
by ONEEYEMAN
Hi,
Please do not post the real code for security reasons. ;-)
So out of curiosity - what happen when the user doesn't enter the PIN or enters it incorrectly? Will there be a confirmation dialog? Will he need to enter it again?
Or how does the program can continue execution without valid PIN?

As far as I understand all you need to do is to have the dialog that will be either shown or hiddden (unless the layer library already have it) and call this dialog from the library. And in the Show() you just display the appropriate dialog and then in the Hide() you dismiss it/close it.

I presume the library will take care of the rest.

Re: using wxWidgets in library

Posted: Tue Mar 12, 2019 5:35 pm
by ppsmurf
ONEEYEMAN wrote: Tue Mar 12, 2019 5:15 pm So out of curiosity - what happen when the user doesn't enter the PIN or enters it incorrectly? Will there be a confirmation dialog? Will he need to enter it again?
Or how does the program can continue execution without valid PIN?
There is probably a timer so if user doesn't enter the PIN on time, it simply calls "Hide()" and throws exception something like "user cancled". If user enters wrong PIN, just "Hide()" and throws exception. No user can not enter PIN second time.
ONEEYEMAN wrote: Tue Mar 12, 2019 5:15 pm As far as I understand all you need to do is to have the dialog that will be either shown or hiddden (unless the layer library already have it) and call this dialog from the library. And in the Show() you just display the appropriate dialog and then in the Hide() you dismiss it/close it.

I presume the library will take care of the rest.
Yes, that's right, but the part between show and hide is out of my reach.