|
I tried Randor's Do Loop with WaitForSingleOject, but it didn't work out.
So I said heck with it, and changed the programs unattended mode to run automatic but visible.
Does the CloseHandle delete the memset, or do I have to do that manually?
|
|
|
|
|
jkirkerx wrote: I tried Randor's Do Loop with WaitForSingleOject, but it didn't work out.
What type of problem were you having? The do/while loop sample was given because that appeared to be what you were trying to accomplish in your original post.
jkirkerx wrote: Does the CloseHandle delete the memset, or do I have to do that manually?
The question does not make any sense. If you are referring to the variables si and pi in my code sample... they are local variables created on the stack and you do not need to perform any clean-up. The memset call is required because the STARTUPINFO struct needs to be initialized to zero to avoid passing garbage to the CreateProcess function. The only cleanup you would need to do is close the handles in the PROCESS_INFORMATION struct.
If you are looking for a complete function to copy and paste that will launch a process and wait for it to complete... the post by Chuck O'Toole will do just fine. Something tells me there is more your not telling us... but when I consult my magic 8 ball it says 'Ask again later'.
Best Wishes,
-David Delaune
|
|
|
|
|
That was last night after hours of coding. I will try and recreate what I had the first time.
The first time, I ran the WaitForSingleObject Loop. I was in new territory as to not knowing what to expect. The CreateProcess fired off the program, the do loop started and ran my cosmetics 1 time, then it read the while statement and paused, waiting for the CreateProcess to finish. So I played around with infinite, and determined that I don't know how to get multiple things to occur at once.
Verbatim Code: hand typed
if (CreateProcess( parameters )
{
do {
SendMessage(ProgressBar, (WPARAM)idx, NULL);
if (idx == 100)
idx = 0;
idx++;
} while (WaitForSingleObject(pi.hProcess, INFINITE) == WAITOBJECT_0);
So then I just modified the code a bit to add the flavors of Chuck to it. Instead of working on the loop more, I created the SendMessage to let the parent window know that the gig was up.
CA_Windows *caWin = new CA_Windows;
bAreWeX64 = caWin->_getProcessorArchitecture();
lp_Parameters = caWin->_create_SQL_Installation_Parameters( bAreWeX64 );
caWin = NULL;
lp_File = sz_SQLServer_Install_FileName;
lp_Directory = sz_SQLServer_Install_FolderPath;
STARTUPINFO si;
PROCESS_INFORMATION pi;
int exit_status = 0;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
if ( CreateProcess(lp_File, lp_Parameters, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, 0, lp_Directory, &si, &pi) )
{
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, (unsigned long *)&exit_status);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
SendMessage(g_SQLServer_Install_MDIWindow, WM_COMMAND, (WPARAM)g_SQLServer_Install_IDC, (LPARAM)g_SQLServer_Install_IDM );
Sleep(2000);
}
Keep in mind that the program takes 30 minutes to run, so I ran the program like 12 times, while adjusting the unattended startup parameters. Then I had to modify the other programs to create the correct parameters for CreateProcess.
I did leave last night with everything working, and I converted all my ShellExecutes to CP today and tested. I was tired when I left, but will pursue the cosmetics again.
|
|
|
|
|
jkirkerx wrote: The CreateProcess fired off the program, the do loop started and ran my cosmetics 1 time
If you look closely at the code sample I gave you... there is a comment:
How to pump the message queue C++[^]
I believe the old VB function for this was DoEvents which was probably implemented something like this:
VOID DoEvents()
{
MSG m;
while(::PeekMessage(&m, NULL, 0, 0, PM_NOREMOVE))
{
if(::GetMessage(&m, NULL, 0, 0))
{
::TranslateMessage(&m);
::DispatchMessage(&m);
}
else
{
break;
}
}
}
If you do not pump the message queue... your dialog will become unresponsive and unable to paint properly. There are typically two ways software engineers tackle this problem:
1.) Put the blocking calls such as WaitForSingleObject in a separate thread.
2.) Wait a small amount of time such as 1 quantum (10 ms on Windows platform) and pump the message queue.
If you copy the code above that pumps the message queue into the do/while loop I gave you...that is waiting 10 milliseconds... your GUI should become responsive. Or you can move everything into a new thread. The choice is yours.
Also... I have noticed that you keep using INFINITE (-1) as the wait time in WaitForSingleObject. This is perfectly correct if you put that function call into a separate thread... however if you are doing this in your dialog window.... WaitForSingleObject will block everything (just as you described).
If you want to continue using a single threaded approach and do all of this from within your dialog window... it is mandatory that you pump the message queue if you want your window to repaint and respond to messages. Try something like this:
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if(CreateProcess(lpApplicationpath,lpCommandline, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, 0, lpCurrentdirectory, &si, &pi))
{
while(WAIT_TIMEOUT == WaitForSingleObject(pi.hProcess, 10))
{
while(::PeekMessage(&oMSG, NULL, 0, 0, PM_NOREMOVE))
{
if(::GetMessage(&oMSG, NULL, 0, 0))
{
::TranslateMessage(&oMSG);
::DispatchMessage(&oMSG);
}
else
{
break;
}
}
}
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
Looking at the source code you have presented, I do not see any other problems. In an earlier post you were asking about 'variable clean-up'... your caWin variable is being created on the heap and definitely qualifies as something that should be deleted when your finished with it.
Let me know how it turns out, it is Thanksgiving and I have free time this weekend for getting fat on turkey/pumpkin pie and answering c++ questions.
Best Wishes,
-David Delaune
|
|
|
|
|
Thanks Dave,
I just hand typed the code in, setup a test environment, and will now take it for a test run.
It took awhile for me to absorb the info.
Yes that loops, I looked at the oMSG out of curiosity, but didn't really understand it. I'm not sure what I'm taking a peek at. Perhaps it's the conversation between the CreateProcess thread and the current window.
Give me some time to see if I can figure out where and how to put my cosmetics back in.
STARTUPINFO si;
PROCESS_INFORMATION pi;
int exit_status = 0;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
if ( CreateProcess(lp_File, lp_Parameters, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, 0, lp_Directory, &si, &pi) ) {
while(WAIT_TIMEOUT == WaitForSingleObject(pi.hProcess, 10)) {
MSG oMSG;
while(::PeekMessage(&oMSG, NULL, 0,0, PM_NOREMOVE)) {
if(::GetMessage(&oMSG, NULL, 0,0) ) {
::TranslateMessage(&oMSG);
::DispatchMessage(&oMSG);
}
else {
break;
}
}
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
SendMessage(g_SQLServer_Install_MDIWindow, WM_COMMAND, (WPARAM)g_SQLServer_Install_IDC, (LPARAM)g_SQLServer_Install_IDM );
Sleep(2000);
}
modified 27-Nov-11 15:21pm.
|
|
|
|
|
jkirkerx wrote: It took awhile for me to absorb the info.
Actually I think it was my fault... if you look at the first code sample I gave you... the do/while loop is checking for the WAIT_OBJECT_0 condition. That is actually incorrect in that specific context. It should actually be looping and checking for the WAIT_TIMEOUT condition while pumping the message queue. I secretly fixed that little error in my last post.
Best Wishes,
-David Delaune
|
|
|
|
|
I noticed that, but didn't question it, was focused on the message pump.
Well it works like a rolex now. I can cancel the installation, and it exits clean. I put my cosmetics in, but changed it to a more simple format. I put a flipflop in, but can't remember how to flipflop with a simple command. bFlipFlop++ or something.
The progress bar updates clean, and I can grab the main window, and mdi child and move it around while running now. Overall, the end results is a much cleaner operation, and all the gears seem to be turning right now.
I need to go back and load you up with some 5's for the help. And then update the rest of my code after further testing to confirm I got it right. The upgrade was well worth the effort, and I learned more about the messaging system today.
I'm not sure if I'm done, but wish to thank you for helping me to get a better understanding of win32 api.
The sample should give you a good idea of what I'm up to, perhaps there's something in the message that can tell me if the user canceled the operation, versus the operation exiting clean.
CA_Windows *caWin = new CA_Windows;
bAreWeX64 = caWin->_getProcessorArchitecture();
lp_Parameters = caWin->_create_SQL_Installation_Parameters( bAreWeX64 );
caWin = NULL;
lp_File = sz_SQLServer_Install_FileName;
lp_Directory = sz_SQLServer_Install_FolderPath;
STARTUPINFO si;
PROCESS_INFORMATION pi;
int exit_status = 0;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
int ndx = 0;
BOOL bFlipFlop = FALSE;
if ( CreateProcess(lp_File, lp_Parameters, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, 0, lp_Directory, &si, &pi) ) {
while(WAIT_TIMEOUT == WaitForSingleObject(pi.hProcess, 10)) {
MSG oMSG;
while(::PeekMessage(&oMSG, NULL, 0,0, PM_NOREMOVE)) {
if(::GetMessage(&oMSG, NULL, 0,0) ) {
::TranslateMessage(&oMSG);
::DispatchMessage(&oMSG);
}
else {
break;
}
if (bFlipFlop == TRUE) {
SetWindowText(g_SQLServer_Install_Progress_Bar, L"Installing SQL Server Express 2008 Advanced");
}
else {
SetWindowText(g_SQLServer_Install_Progress_Bar, L"Installation may take up to 30 minutes");
}
SendMessage(g_SQLServer_Install_Progress_Bar, PBM_SETPOS, (WPARAM)ndx, 0);
UpdateWindow(g_SQLServer_Install_MDIWindow);
if (ndx != 99) {
ndx++;
}
else {
ndx = 0;
}
}
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
SendMessage(g_SQLServer_Install_MDIWindow, WM_COMMAND, (WPARAM)g_SQLServer_Install_IDC, (LPARAM)g_SQLServer_Install_IDM );
Sleep(2000);
|
|
|
|
|
Hi,
jkirkerx wrote: Well it works like a rolex now. I can cancel the installation, and it exits clean. I put my cosmetics in, but changed it to a more simple format. I put a flipflop in, but can't remember how to flipflop with a simple command. bFlipFlop++ or something.
Love the analogy. What do you mean by flipfop? Are you referring to bit flipping?
bool b = true;
while(1)
{
b = !b;
}
jkirkerx wrote: I need to go back and load you up with some 5's for the help.
Nah, don't do that... I don't come here for 5's. I wish the reputation system would go away, it cheapens the website... I want my old codeproject back.
jkirkerx wrote: I'm not sure if I'm done, but wish to thank you for helping me to get a better understanding of win32 api.
Now that's why I come here, a 'thank you' is worth much more than a 5.
jkirkerx wrote: The sample should give you a good idea of what I'm up to, perhaps there's something in the message that can tell me if the user canceled the operation, versus the operation exiting clean.
Put back that call to GetExitCodeProcess... that could potentially tell you if the user cancelled the operation. The Microsoft SQL Server Express 2008 may or may not return a different value based on cancellation...
Best Wishes,
-David Delaune
|
|
|
|
|
Cool!
flip the progress message every cycle of 100,
BOOL bFlipFlop = FALSE
if 100, bFlipFlop = TRUE
I'll try your example and examine the exit code.
|
|
|
|
|
jkirkerx wrote: flip the progress message every cycle of 100,
Outside of your while loop declare an unsigned integer and increment the integer inside your loop. Use the Modulus Operator (%)[^] and if the remainder is zero then the integer value is divisible by 100... do your magic.
unsigned int value = 0;
while(1)
{
++value;
if(0 == (value % 100))
{
}
}
Best Wishes,
-David Delaune
|
|
|
|
|
Sorry I took so long.
That sounded so over whelming at the time I read the message. I didn't want to make any more threads because I didn't really understand WaitForSingleObject at the time.
At the time, I was getting trapped in the new thread, and couldn't figure out how to get out of it for a second to start another thread for WaitForSingleObject. I was in a thread jail cell with no key.
I think I get it now, or at least more so I can implement more advanced code concepts now. It does make my program run smoother, and now the cosmetics update faster and smoother as intended.
|
|
|
|
|
I have an SDI application, with a splitter window that have in left view an CTreeView and right side an CListView.In each one I have some items. I override PreTranslateMessage in each one to be able on tab key to move focus from tree to view and viceversa :
BOOL CMyTree::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_TAB)
{
CMyListView* pView = (CMyListView*)pChild->GetMyListView();
pView->SetFocus();
pView->GetListCtrl().SetItemState(0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
}
return TRUE;
}
return CTreeView::PreTranslateMessage(pMsg);
}
I see that the focus has moved.
Somewhere in menu I have a delete menu that could delete items from tree or from listview.
Let's say that I'm in treeview. I press tab and I see that the focus has moved on listview. When I try to delete an item I see that I delete an item from treeview not from list view .... so, from some reason, the focus remained in treeview ...
The the deletion goes well only when I move the focus from tree on list view by click with mouse in list view ...
My question is, is enough to call SetFocus(); to move an focus from tree view to listview ?
|
|
|
|
|
How does your command handler for the delete operation determine whether the treeview or the listview has focus? You haven't provided that code. As a user, my expectation would be that the delete operation should be deleting the item in the control that has focus. Though I guess a case could be made for deleting anything that is selected regardless of focus.
Chris Meech
I am Canadian. [heard in a local bar]
In theory there is no difference between theory and practice. In practice there is. [Yogi Berra]
posting about Crystal Reports here is like discussing gay marriage on a catholic church’s website.[Nishant Sivakumar]
|
|
|
|
|
Of course that program delete the item of window that have the focus ... the problem is : I am in the listview, I select 2 items, and when I go to main menu, click on delete item from menu, program wants to delete an tree view item, not list view items ... I try to make a little demo, to see what is happend.
|
|
|
|
|
If we could see your 'delete' code, that could help. That command handler code could delete items from either control.
Chris Meech
I am Canadian. [heard in a local bar]
In theory there is no difference between theory and practice. In practice there is. [Yogi Berra]
posting about Crystal Reports here is like discussing gay marriage on a catholic church’s website.[Nishant Sivakumar]
|
|
|
|
|
void CMyTree::OnEditDelete()
{
CString sItem,sMessage;
CTreeCtrl& Tree = GetTreeCtrl();
HTREEITEM hSelectedItem = Tree.GetSelectedItem();
if(! hSelectedItem)return;
sItem = Tree.GetItemText(hSelectedItem);
sMessage.Format(_T("Are you sure you want to delete '%s' item ?"),sItem);
if(IDYES != MessageBox(sMessage,NULL,MB_YESNO | MB_ICONWARNING))return;
}
theApp.UpdateAllViews(NULL,CMyApp::UH_ITEM_CHANGED);
}
the code for delete an item from list view is similar, but at the point when I have confirm message-box, the message said to me that want to delete item from listview, not from tree view ....
I don't know if I'm was understable, but thank you anyway for your interest !!!!
modified 26-Nov-11 1:17am.
|
|
|
|
|
[CListCtrl::DeleteItem] Deletes an item from a list view control.
CListCtrl* pmyListCtrl;
int nCount = pmyListCtrl->GetItemCount();
for (int i=0;i < nCount;i++)
{
pmyListCtrl->DeleteItem(0);
}
|
|
|
|
|
Looking at (ATL) code of mine for handling tabs, and which uses <code>GetDlgItem</code> rather than <code>SetFocus</code>, the only difference I can see is that I have a call:<pre>// Now select all like normal tab behaviour
SendMessage(hNew, EM_SETSEL, 0, -1);</pre>at the end. Presumably as my tabs have edit controls on and the cursor needs setting up. So unless there's a parallel with your views e.g. ensure, say, a node or list item has focus or is other wise set up, I'd agree with Chris and wonder about the code doing the deleting.
|
|
|
|
|
Hi all,
I'm new with Win C++ API, I'm trying to create an application that lives as a trayicon, and my purpose is to capture the mouse over event when hovering over the icon..this should launch a new window. I've had some try by using the WM_MOUSEHOVER message on the window handler relative to the NOTIFYICONDATA object, but it seems to have no effect. Am I using the message in a wrong way? Is there some specific API or implemaentation to manage this?
Thank you all in advance!!
|
|
|
|
|
[ Here ] are a couple of good implementations.
|
|
|
|
|
Hi,
This link will help you.
http://www.codeproject.com/KB/shell/ctrayiconposition.aspx
-- modified 25-Nov-11 4:09am.
|
|
|
|
|
Please make your links clickable, like this[^].
Unrequited desire is character building. OriginalGriff
I'm sitting here giving you a standing ovation - Len Goodman
|
|
|
|
|
Hi developers,
I requires to handle OnClose handle of a form view. I am building a heavy tree on it( based on thread ), and while doing that if i closed that form, application was getting crash, because that tree control has been destroyed.
So that I have to capture it's close event so that I can prevent this event to proceed, i.e. to close that form.
Thanks In Advance.
Amrit Agrawal
Software Developer
|
|
|
|
|
When you close that form, the syst will call its destructor so if you wanna handle the prob go to the
YourFormClass()::~YourFormClass( )
{
}
"The Ultimate Limit Is Only Your Imagination."
|
|
|
|
|
|