|
It is not possible but you can cheat. Reverse engineer it.
Create a Windows app (win32 or MFC) and redirect messages to a console window.
But once you add a window, your app will no longer be a console app.
So it is still not possible.
See [this].
More reversed console apps [here] and [here].
|
|
|
|
|
Here is another example, to go along with Carlos'.
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous
|
|
|
|
|
Hi,
I have gotten arount Most of the security challenges around the New Windows Model.
One issue remains a challenge. I created a derrived MFC Control: 'CMultiColumListBox', derived from MFC-'CListBox'. It in turn, is used as a Baseclass for various data tabulations. it all works to perfection under Win 95/98. Win NT, and Windows XP. With Vista and Windows 7, the Header Button listtakes up about 80% of the width of the CListbox Window, the Text Colums take up even Less.
One part of the creation process sets up the display Geometry parameters. I must have missed a Translation Somewhere.
The Salient part of the control that does this is as follows:-
BOOL CMultiColumListBox::RegisterControl(CDialog * pDialog)
{
if(!m_bDrawButtons)return TRUE;
ASSERT(pDialog->IsKindOf( RUNTIME_CLASS(CWnd) ) );
ASSERT(::IsWindow(pDialog->m_hWnd));
CDC* pDC=pDialog->GetDC();
ASSERT(pDC);
m_pParentDialog=pDialog;
CRect CtrlRect,DlgWndRect,DlgClientRect,BnRect;
GetWindowRect(&CtrlRect); pDialog->GetWindowRect(&DlgWndRect);
pDialog->GetClientRect(&DlgClientRect);
int BorderWidth=DlgWndRect.Width() - DlgClientRect.Width();
int TitleBarHeight=DlgWndRect.Height() -
DlgClientRect.Height()-BorderWidth;
BorderWidth/=2;
int Base_x,Base_y,BaseWidth;
Base_x=CtrlRect.left-1;
Base_y=CtrlRect.top;
BaseWidth=CtrlRect.Width();
for(int i=0;i<m_nNrOfColumns;i++){
CWnd* pWnd=pDialog->GetDlgItem(m_nColumList[i].n_ID);
ASSERT(pWnd);
pWnd->ShowWindow(SW_NORMAL);
int Width=m_nColumList[i].width;
if(i==m_nNrOfColumns-1)Width=BaseWidth;
if(Width>BaseWidth)Width=BaseWidth;
BnRect.left=Base_x-DlgWndRect.left-BorderWidth;
BnRect.right=Base_x+Width-DlgWndRect.left-BorderWidth;
BnRect.top=Base_y-m_nItemHeight*2-TitleBarHeight-DlgWndRect.top-1;
BnRect.bottom=Base_y-TitleBarHeight-DlgWndRect.top-1;
pWnd->MoveWindow(&BnRect); Base_x+=Width;
BaseWidth-=Width;
char* p=m_nColumList[i].lpcstrColumHeader;
if(p)pWnd->SetWindowText(p);
}
return TRUE;
}
This function would Typicaly be called from OnInitDialog()from the Dlg that contains it. It sets the Parameters for subsequent Drawing and Painting.
Any Idea about DlgToScreen() ScreenToDlg(),etc tha should have been used here
Bram van Kampen
|
|
|
|
|
i have a character arry in C
hello hi soidjosdc
kcopsdkcpok cjsdp
dskcoksdpc ocsdkcpd
i want to read it line by line and store it in another array....please help
|
|
|
|
|
please give any suggestions
|
|
|
|
|
Okay, I'll byte..
In essence, you have a string that you have to cut up into smaller pieces.
The cut-points are clearly defined - the string is to be cut at the end of each line of text.
So, we need
1) knowledge of the number of lines
2) memory to hold each of the lines
3) to copy each of the lines to the memory allocated in step 2.
Sooo, you'll need to know what your line-ending character(or sequence) is. You'll need to count the number of instances of the of line terminators, and for ease and simplicity, add 1 to this number - this is the number of lines you have - mLineCount.
You can then create an array of mLineCount elements of char*
You can then copy each line, storing the address of the new text into the appropriate array element.
Two functions you'll likely make use of are strdup and strtok. I advise you read the documentation for these two functions carefully, there are a few gotchas or things to watch for with strtok - Particularly, the fact that it modifies the input string. This precludes the use of the function on const char* strings.
For example, while the intention below is to split "some text" into two separate strings, it will fail since strtok can't modify myString.
char *myString = "some text", *delims = ",. ";
char *curToken;
curToken = strtok(myString, delims);
|
|
|
|
|
I and others already answered a similar query below. If you still don't understand string parsing then you need to spend a lot of time reading the MSDN documentation and sample code on the functions I recommended to you.
Unrequited desire is character building. OriginalGriff
I'm sitting here giving you a standing ovation - Len Goodman
|
|
|
|
|
You may hand-craft it, for instance:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main()
{
int n, count;
int item, lastindex;
char ** b;
const char a[] = "hello hi soidjosdc\nkcopsdkcpok cjsdp\ndskcoksdpc ocsdkcpd";
const int LEN = sizeof(a);
for (n=0, count = 0; n<LEN; n++)
{
if (a[n] =='\n' || a[n] == '\0')
count++;
}
b = (char **) malloc( count * sizeof(char *));
assert(b);
for (n=0, item=0, lastindex = 0; n<LEN; n++)
{
if (a[n] =='\n' || a[n]=='\0')
{
int k, len;
len = n-lastindex;
b[item] = (char *) malloc(len+1);
assert(b[item]);
for (k=0; k<len;k++)
{
b[item][k] = a[lastindex+k];
}
b[item][k] = '\0';
lastindex = n+1;
item++;
}
}
for (item=0; item<count; item++)
{
printf("%s\n", b[item]);
}
for (item=0; item<count; item++)
{
free(b[item]);
}
free(b);
return 0;
}
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
That's what I'm talkin' about.
I love your cruel avoidance of the simplifying (though functionality hiding) strdup and strtok.
|
|
|
|
|
enhzflep wrote: That's what I'm talkin' about.
In fact I just spoon-fed the OP with your method.
enhzflep wrote: I love your cruel avoidance of the simplifying (though functionality hiding) strdup and strtok.
Yes, that's my own departure: why should we use a function when we've the 'metal'?
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
I want to run a do loop, for cosmetic purposes while WaitForSingleObjectEx is monitoring the ShellExecuteEx Thread.
I'm looking for something to grab onto, for the while statement to monitor, and then release to close the handle.
The hProcess !- NULL, is not working well, or I'm calling the code in the wrong order or something.
exit_Code = ShellExecuteEx(&lpExecInfo);
if (lpExecInfo.hProcess != NULL) {
DWORD iWait = WaitForSingleObjectEx(lpExecInfo.hProcess, INFINITE, TRUE);
int ndx = 0;
do {
ndx++;
} while ( lpExecInfo.hProcess !=NULL );*/
CloseHandle(lpExecInfo.hProcess);
|
|
|
|
|
Your loop is unnecessary. The call to WaitForSingleObjectEx() is going to block unitl the process you are monitoring is complete.
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]
|
|
|
|
|
Your right about that. It's one or the other.
|
|
|
|
|
Hi,
As Chris pointed out... by the time your do-while loop has started the processes will have ended. I would also recommend that you use CreateProcess rather than ShellExecute.
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
if(CreateProcess(lpApplicationpath,lpCommandline, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE|NORMAL_PRIORITY_CLASS, 0, lpCurrentdirectory, &si, &pi))
{
int index = 0;
do
{
++index;
} while (WAIT_OBJECT_0 = WaitForSingleObject(pi.hProcess,10););
}
Best Wishes,
-David Delaune
|
|
|
|
|
The program takes 30 minutes to run, I'll give create process a whirl
|
|
|
|
|
Here's what I use
int CWelcomeWizardDlg::RunAppAndWait(char *cmd)
{
PROCESS_INFORMATION ProcInfo;
STARTUPINFO StartInfo;
int exit_status = 0;
memset(&StartInfo, 0, sizeof(StartInfo));
StartInfo.cb = sizeof(StartInfo);
if (CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &StartInfo, &ProcInfo))
{
WaitForSingleObject(ProcInfo.hProcess, INFINITE);
GetExitCodeProcess(ProcInfo.hProcess, (unsigned long *)&exit_status);
CloseHandle(ProcInfo.hProcess);
CloseHandle(ProcInfo.hThread);
return exit_status;
}
return 1;
}
|
|
|
|
|
Thanks Chuck. Let's see what create process does.
|
|
|
|
|
And as Chuck will attest, put the waitforsingleobject into a seperate thread otherwise you risk blocking your windows messaging.
==============================
Nothing to say.
|
|
|
|
|
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);
|
|
|
|
|