Refresh CDialog MFC in the same dialog class - mfc

Is there any way to refresh() MFC CDialog in the same class?
I have tried using Invalidate(), RedrawWindow(), UpdateWindow() without success...
I would appreciate any kind of help.

You have to close the program and run the program again.
Use GetModuleFileName to find your app name. Run the program with CreateProcess.
You can add a command line argument after applications path, for example " /restart?mydialog", so that when the program restarts, it can examine the commandline argument and launch the appropriate dialog. Example:
void CMyDialog::OnSettings()
{
wchar_t buf[MAX_PATH];
GetModuleFileName(NULL, buf, _countof(buf));
wcscat_s(buf, L" /restart?mydialog");
AfxGetMainWnd()->SendMessage(WM_CLOSE);
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
CreateProcess(NULL, buf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
}
Now go to CMainFrame, CMyMDIFrameWnd, or whichever is the application's main window, and get ready to launch the dialog when L"/restart?mydialog" appears in the command line. Example:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
...
CString s = GetCommandLine();
if (s.Find(L"/restart?mydialog") >= 0)
PostMessage(WM_COMMAND, ID_APP_ABOUT); //<== launch the correct dialog here
return 0;
}

Related

Read process's 'stdout' output in Win32 C++ Desktop Application

I started a Visual C++ Desktop Application (win32) and created a button, that creates a process.
Here is the button code:
INT_PTR CALLBACK Btn_Click(HWND hWnd)
{
wchar_t cmd[] = L"cmd.exe /c testprogram.exe";
STARTUPINFOW startInf;
memset(&startInf, 0, sizeof startInf);
PROCESS_INFORMATION procInf;
memset(&procInf, 0, sizeof procInf);
BOOL p = CreateProcess(NULL, cmd, NULL, NULL, TRUE,
CREATE_NO_WINDOW, NULL, NULL, &startInf, &procInf);
if (p)
{
CloseHandle(procInf.hProcess);
CloseHandle(procInf.hThread);
}
return TRUE;
}
I want to read the process's stdout output (cmd.exe or testprogram.exe) while it is 'running' and set it as a string. After setting the content of a created Text input.
I tried this answer, but it freezes the application. (because of ReadFile() and while() loop)
How to read output from cmd.exe using CreateProcess() and CreatePipe()
I searched the forum for a better answer, but every example is for a console app.
Update:
I can read the output of ping.exe but the window stays frozen until ping.exe closes. the for() loop (and ReadFile()) blocks the window .
wchar_t command[] = L"ping localhost";
STARTUPINFOW startInf;
memset(&startInf, 0, sizeof startInf);
PROCESS_INFORMATION procInf;
memset(&procInf, 0, sizeof procInf);
HANDLE cout_r = NULL;
HANDLE cout_w = NULL;
SECURITY_ATTRIBUTES sec_a;
//memset(&sec_a, 1, sizeof sec_a);
sec_a.nLength = sizeof(SECURITY_ATTRIBUTES);
sec_a.lpSecurityDescriptor = NULL;
CreatePipe(&cout_r, &cout_w, &sec_a, 0);
SetHandleInformation(cout_r, HANDLE_FLAG_INHERIT, 0);
//startInf.cb = sizeof(STARTUPINFO);
startInf.hStdOutput = cout_w;
startInf.dwFlags |= STARTF_USESTDHANDLES;
BOOL p = CreateProcess(NULL, command, NULL, NULL, TRUE,
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL,
&startInf, &procInf);
if (p)
{
CloseHandle(procInf.hProcess);
CloseHandle(procInf.hThread);
CloseHandle(cout_w);
}
else
{
SetWindowTextA(hedit, "Failed");
}
char buf[1024];
CHAR chBuf[4096];
DWORD dwRead;
for (;;)
{
BOOL bSuccess = ReadFile(cout_r, chBuf, 4096, &dwRead, NULL);
if (!bSuccess || dwRead == 0) break;
std::string s(chBuf, dwRead);
std::wstring stemp = std::wstring(s.begin(), s.end());
OutputDebugStringW(stemp.c_str());
}
I searched for asynchronous I/O on ReadFile and pipes.
If anyone can provide me an example on how to do async Readfile without for() loop would be good.
If your UI thread stops pumping messages Windows treats it as frozen. This means you should not perform blocking I/O on this thread.
You could use asynchronous (overlapped) I/O with ReadFile but doing the whole child process operation in another thread is a lot easier. The button press would start the thread and once the thread has read stdout it can signal back to your main window by sending a WM_APP message.

Problem trying to start a runnable jar from a C++ application

I need to develop a .exe file that will launch a runnable .jar file which is stored on a subfolder called core. I built the C++ .exe application with sublime text and mingw and it's working fine but there is a small problem that I need to solve. When you execute the .exe file, during a minimum portion of time you can see a black window on screen which is disappearing in some milliseconds and after it the Java .jar application opens. This only happens if I use this .exe. If I double click in the runnable jar the black window doesn't appear.
How can I avoid that black window which dissapears in some milliseconds?
This is the code:
#include <windows.h>
int main()
{
ShellExecute(0, "open", "core.jar", NULL, "core", SW_SHOW);
return 0;
}
I tried also with this code and same result:
ShellExecute(0, "open", "cmd.exe", "/C .\\core\\core.jar", 0, SW_HIDE);
I'm aware there are other similar questions but none of them works for this problem and none of them seems to be applicable to Sublime and gcc.
The problem isn't your call to ShellExecute. Your code is for a console application. Console applications, as one might guess, run in a console (that black window; same as you'd get if you ran cmd.exe).
You can just replace main with WinMain, and simply call ShellExecute in there to launch the jar, and there should be no resulting console window (assuming the jar itself isn't creating one).
See 14 B for how to make a 'windows' app with MingW.
Use CreateProcess() or ShellExecuteEx() which will return you handle to the created process, and with that handle you can kill the process.
Here is an example showing how this works including error handeling.
#include <windows.h>
#include <string>
#include <iostream>
void DisplayError(LPCTSTR errorDesc, DWORD errorCode)
{
TCHAR errorMessage[1024] = TEXT("");
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
| FORMAT_MESSAGE_MAX_WIDTH_MASK;
FormatMessage(flags,
NULL,
errorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
errorMessage,
sizeof(errorMessage) / sizeof(TCHAR),
NULL);
std::cerr << "Error : " << errorDesc << "\n";
std::cerr << "Code = " << errorCode << "\n";
std::cerr << "Message = " << errorMessage << "\n";
}
int main()
{
STARTUPINFO info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
ZeroMemory(&info, sizeof(info));
info.cb = sizeof(info);
ZeroMemory(&processInfo, sizeof(processInfo));
std::string path = "D:\\Java\\jdk1.6.0_26\\bin\\java.exe";
std::string cmdArgs = "java.exe -jar D:\\temp\\sample.jar";
// Start the child process.
if (CreateProcess(path.c_str(), const_cast<char *>(cmdArgs.c_str()), NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
{
// Wait until child process exits.
WaitForSingleObject(processInfo.hProcess, INFINITE);
// Close process and thread handles.
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
else
{
DWORD errorCode = GetLastError();
DisplayError(TEXT("Unable to execute."), errorCode);
}
//system("pause");
}
Finally I discovered that is enough with adding -mwindows to the gcc compile command:
gcc -o launcher launcher.cpp -mwindows

C++ - Process launched from another process is not killed when an initial one is killed

I have a problem that a process created inside of another one is left, when the parent one is killed with something like 'kill task'. More precisely, application launches general_service.exe. Inside of this service, I launch a new logger_runner.exe. When main application stops, it just kill general_service.exe, but in task manager I see my logger_runner.exe. When I stop general_service.exe in VS, it is left as well.
How to make my logger_runner depends on general_service ?
Thanks for the help!
This function starts my .exe
void startLogger(PROCESS_INFORMATION & processInformation) {
std::wstring commandLine = L"\"" + PathUtils::programFolder() + LR"(\logger_runner.exe)" + L"\"";
STARTUPINFOW startupInfo;
memset(&startupInfo, 0, sizeof(startupInfo));
memset(&processInformation, 0, sizeof(processInformation));
wchar_t* commandLineCopy = _wcsdup(commandLine.c_str());
if (!CreateProcessW(NULL, // No module name (use command line)
commandLineCopy, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&startupInfo, // Pointer to STARTUPINFO structure
&processInformation) // Pointer to PROCESS_INFORMATION structure
)
{
free(commandLineCopy);
throw SystemException();
}
free(commandLineCopy);
}
This function should ends logger_runner.exe
void closeLogger(PROCESS_INFORMATION & processInformation) {
// Check exit code
DWORD exitCode = 0;
GetExitCodeProcess(processInformation.hProcess, &exitCode);
if (TerminateProcess(processInformation.hProcess, 0) == 0) {
std::cerr << "Could not terminate logger process\n";
}
// Close process and thread handles.
CloseHandle(processInformation.hProcess);
CloseHandle(processInformation.hThread);
}
All these functions are called inside of the wrapper
class LoggerWrapper {
public:
LoggerWrapper() {
startLogger(m_processInformation);
};
~LoggerWrapper() {
closeLogger(m_processInformation);
}
private:
PROCESS_INFORMATION m_processInformation;
};
In wmain function of my general_service solution, I just call
LoggerWrapper logger

How can I show a wait cursor from the moment I invoke the popup dialog until the dialog is visible to the user?

So, I want to display a CDialog to the user:
void CMeetingScheduleAssistantDlg::OnOptionsOutlookCalendarOptions()
{
COutlookCalendarSettingsDlg dlgSettings(this);
dlgSettings.DoModal();
}
Now, the popup dialogue (in OnInitDialog) runs a console application behind the scenes. This console application is communicating with Microsoft Graph.
As a result, it can take a few seconds for the dialog to display.
I execute the console application with this method:
bool CMeetingScheduleAssistantApp::ExecuteProgram(CString strCommand, DWORD& rExitCode)
{
PROCESS_INFORMATION processInformation = { nullptr };
STARTUPINFO startupInfo = { 0 };
int nStrBuffer;
BOOL bProcessResult, bExitCodeProcess;
bool bOK = false;
CWaitCursor wait;
SetProgramExecuting(true);
rExitCode = -1;
startupInfo.cb = sizeof(startupInfo);
nStrBuffer = strCommand.GetLength() + 50;
bProcessResult = CreateProcess(nullptr, strCommand.GetBuffer(nStrBuffer),
nullptr, nullptr, FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW,
nullptr, nullptr, &startupInfo, &processInformation);
strCommand.ReleaseBuffer();
if (!bProcessResult)
{
// CreateProcess() failed
// Get the error from the system
LPVOID lpMsgBuf;
DWORD dw = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, nullptr);
// Display the error
CString strError = (LPTSTR)lpMsgBuf;
TRACE(_T("Authenticate failed at CreateProcess()\nCommand=%s\nMessage=%s\n\n"), strCommand, strError);
// Free resources created by the system
LocalFree(lpMsgBuf);
SetProgramExecuting(false);
// We failed.
return false;
}
else
{
// Successfully created the process. Wait for it to finish.
DWORD WaitResult;
do
{
WaitResult = MsgWaitForMultipleObjects(1,
// only 1 wait object
&processInformation.hProcess, // worker thread
FALSE, // stop if any
INFINITE, // no timeout
QS_ALLINPUT);
if (WaitResult == WAIT_OBJECT_0 + 1)
{
// Handle windows message
MSG Msg;
while (PeekMessage(&Msg, nullptr, 0, (UINT)-1, PM_REMOVE))
{
TRACE3("%d %d %d\n", Msg.message, Msg.wParam, Msg.lParam);
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
} while (WaitResult != WAIT_OBJECT_0);
ASSERT(WaitResult == WAIT_OBJECT_0);
// Get the exit code.
bExitCodeProcess = GetExitCodeProcess(processInformation.hProcess, &rExitCode);
// Close the handles.
CloseHandle(processInformation.hProcess);
CloseHandle(processInformation.hThread);
if (!bExitCodeProcess)
{
// Could not get exit code.
TRACE(_T("Executed command but couldn't get exit code.\nCommand=%s\n"), strCommand);
SetProgramExecuting(false);
return false;
}
SetProgramExecuting(false);
return true;
}
}
Inside OnInitDialog, just before the ExecuteProgram is called, I tried using:
CWaitCursor wait;
But it makes no difference. So how can I show a wait cursor from the moment I invoke the popup dialog until the dialog is visible to the user?
One solution could be to use Modeless Dialog. You can create a dialog which looks similar to wait cursor dialog.
You show that Modeless Dialog just before dlgSettings.DoModal(); statement in your code. Please use TOP_MOST while showing Modeless Dialog.
Finally, hide/close Modeless Dialog from OnInitDialog() once processing is over.
Another approach could be:
Add a public member of asCWaitCursor* m_pWaitCursor in COutlookCalendarSettingsDlg class. Now modify code as
void CMeetingScheduleAssistantDlg::OnOptionsOutlookCalendarOptions()
{
COutlookCalendarSettingsDlg dlgSettings(this);
dlgSettings->m_pWaitCursor = new CWaitCursor();
dlgSettings.DoModal();
}
Then modify OnInitDialog of COutlookCalendarSettingsDlg to delete instance of CWaitCursor before returning from it.
delete m_pWaitCursor;
Update
I thought I would add an update to this answer that applies in other situations. What you do is use a CPersistantWaitCursor instead. The article provides a little example:
#include "PersistentWaitCursor.h"
void CMyWnd::DoSomeLengthyOperation()
{
// Create and show the wait cursor
CPersistentWaitCursor waitCursor;
// Do some lengthy operation
...
// waitCursor goes out of scope and cursor is restored
}
BOOL CMyWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (CPersistentWaitCursor::WaitCursorShown())
{
// We are showing the wait cursor
RestoreWaitCursor();
return TRUE;
}
// Let the base class deal with this one
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
Look at the article for full details about how it works. But I can confirm that for some of my other lengthy actions this enhanced CPersistantWaitCursor did the trick.

CMD Exception Handling C/C++

I will use some CMD commands in my program and these commands might throw some exceptions. And as you know, when an exception accours, CMD writes its own error message the screen. But, I want to write my own error message.
My question is this: Is there a way to block CMD messages and write only my own error messages?
P.S. This is not a complex program. It executes CMD commands using System().
Example:
Let's say, the user can rename and copy any files in the program. As you know, if the user does not enter file's path properly, an error message is showed on the screen. And I want that this error message never appears on the screen. Only my own error message is showed.
Thank you!
It depends on your platform and the commands you are going to use. The usage of system() for calling console commands is by the way strongly discouraged by most people (it's way to heavy for most purposes).
I would suggest to you using CreateProcess() with the CREATE_NO_WINDOW flag and waiting for the process to exit with a call to WaitForSingleObject() and GetExitCodeProcess().
This approach utilizes the fact, that most CMD command are executables, located somewhere in C:/Windows/....
/*
* Executes a program and returns it's exit code.
*
* TODO: Error checking should be added for
* CreateProcess()
* WaitForSingleObject()
* GetExitCodeProcess()
*/
DWORD ExecCmdLine(TCHAR const* cmdline)
{
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(pi));
::CreateProcess(NULL, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
::CloseHandle(pi.Thread);
::WaitForSingleObject(pi.hProcess, INFINITE);
DWORD exitcode;
::GetExitCodeProcess(pi.hProcess, &exitcode);
::CloseHandle(pi.hProcess);
return exitcode;
}
If you want to retrieve the output of the command you could also provide hStdOutput, hStdError in the STARTUPINFO structure and set STARTF_USESTDHANDLES in STARTUPINFO.dwFlags.
You can even do other things in your own program while the command is executing (especially as you mentioned file copy). This one is done the C++ way:
/*
* TODO: Error checking should be added for
* CreateProcess()
* WaitForSingleObject()
* GetExitCodeProcess()
*/
class AsyncCmd
{
public:
AsyncCmd(std::string const& cmdline)
: cmdline(cmdline),
processHandle(NULL)
{
}
~AsyncCmd()
{
if (this->processHandle != NULL)
::CloseHandle(this->processHandle);
}
// Starts the execution of the commandline.
void Start(HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE), HANDLE hErr = GetStdHandle(STD_ERROR_HANDLE))
{
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput = hOut;
si.hStdError = hErr;
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(pi));
::CreateProcess(NULL, this->cmdline.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
::CloseHandle(pi.hThread);
this->processHandle = pi.hProcess;
}
// Blocks until execution is finished and returns the exit code.
DWORD ExitCode()
{
::WaitForSingleObject(this->processHandle, INFINITE);
DWORD exitcode;
::GetExitCodeProcess(this->processHandle, &exitcode);
return exitcode;
}
private:
AsyncCmd(AsyncCmd const&);
AsyncCmd& operator=(AsyncCmd const&);
std::string cmdline;
HANDLE processHandle;
}
To rephrase what's already been said:
Q: Can you somehow intercept an error thrown by a command you've invoked via "system()"?
A: No. For many reasons.
But you can redirect the textual error message that's written by the command line program:
Redirecting "stderr" is relatively easy. "GetStdHandle(STD_ERROR_HANDLE)" is one way. Redirecting to "> :err" is another.
Unfortunately, not all programs are nice enough to write error messages to "stderr".
Many write everything to "stdout".
In the latter case, you'd have to figure out 1) that an error actually occurred, and 2) figure out how to separate the parts of the text input that are "standard output", vs those parts that are "error text".
PS:
An alternative API to "system()" is "popen()".
One brute force way to do it would be to pipe the output of the CMD i.e. yourCommand > file.txt to a file and then read the file contents to determine if there was an exception.
Adding to what yourmt wrote, I'd like to point out that exceptions won't bleed through across process boundaries. So what you are tackling here is the output (both stderr and stdout) of the executed program (and shell) plus its exit code (in case this provides any useful information). This is mostly so you understand that this is literally not about exception handling as your title implies.
That means you can set hStdOutput and hStdError when using CreateProcess/CreateProcessEx to use pipes that you control and where you "catch" the output and then replace it with your own before outputting it to the console. In case you want to only replace stderr you can also do that.
You can use
#include "Exception.h"
class MyClass
{
public:
class Error : public Exception { };
MyClass();
~MyClass();
void myFunction() throw(Error);
}
...
catch (MyClass::Error & error)
{
cout << error.full_message << endl;
return;
}
and
class Exception
{
public:
std::string message;
std::string full_message;
virtual char * info() { return ""; };
void setMessage(std::string msg)
{
message = msg;
if (*info() == 0) { full_message = msg; }
else { full_message = MakeString() << info() << " " << msg; }
}
};
// template function ///////////////////////////////////////////
template <class errType>
void Throw(const std::string msg=std::string(""))
{
errType err;
err.setMessage(msg);
throw(err);
}