Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

NickRepin or Others

Posted on 1998-12-03
10
Medium Priority
?
284 Views
Last Modified: 2013-12-03
This question relates to Ketuts q: Passing Keystrokes.

This is a simile of NicRepins solution:

Hi NickRepin

I have put you suggestions into action:
calc.exe is in the same DIR as Main and it startsup OK.

But we still do not seem to be able to pass keystrokes !!!!!!!!!!!!!!!!!!!!!.

Dialog consists of 3 buttons - IDOK, IDCANCEL and IDD_BUTTON1
I have compiled it with VC++ 5.0 Mulithreaded libs.

#include <windows.h>

BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK EnumProc(HWND, LPARAM);
static HWND hwndeng = 0;
static DWORD dwThreadId;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR lpszCmdLine, int cmdShow) {
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
return 0 ;
}

BOOL CALLBACK DlgProc(HWND hwnd, UINT mMsg, WPARAM wParam, LPARAM lParam) {
PROCESS_INFORMATION       piProcInfo;
STARTUPINFO siStartupInfo;
BOOL bCreate = FALSE;
siStartupInfo.cb =       sizeof(STARTUPINFO);
siStartupInfo.lpReserved = NULL;
siStartupInfo.lpDesktop = NULL;
siStartupInfo.lpTitle = NULL;
siStartupInfo.dwFlags = STARTF_USESHOWWINDOW;
siStartupInfo.wShowWindow = SW_SHOWNORMAL;
siStartupInfo.cbReserved2 = 0;
siStartupInfo.lpReserved2 = NULL;

switch(mMsg) {
case WM_INITDIALOG:
bCreate = CreateProcess("calc.exe",      NULL, NULL, NULL, FALSE,  
NORMAL_PRIORITY_CLASS, NULL, NULL,
&siStartupInfo,
&piProcInfo);

if(bCreate == 0) {
MessageBox(NULL, "Calc - Process Not Found",  NULL, MB_OK | MB_ICONEXCLAMATION);
return TRUE;
}

WaitForInputIdle(piProcInfo.hProcess, 3000);
dwThreadId = piProcInfo.dwThreadId;
return TRUE;

case WM_COMMAND:
switch(LOWORD (wParam)) {
case IDD_BUTTON1:
EnumThreadWindows(dwThreadId, EnumProc, 0);
if(hwndeng == NULL) {
MessageBox(NULL, "Calc - Enum Not Found", NULL, MB_OK | MB_ICONEXCLAMATION);
return TRUE;
}

EnableWindow(hwndeng, TRUE);
SendMessage(hwndeng,  WM_SYSKEYDOWN, VK_F1,       0L);
return TRUE;

case IDOK:
case IDCANCEL:
CloseHandle(piProcInfo.hThread); // not quite sure how to close process !!!!
CloseHandle(piProcInfo.hProcess);
ExitProcess(0);      
EndDialog(hwnd, 0);
return TRUE;
}
break;
}
return FALSE;
}

BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lp) {
if(GetParent(hwnd) == NULL) {
hwndeng = hwnd;
return FALSE;
}
else return TRUE;
}
0
Comment
Question by:wayan
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 5
10 Comments
 

Author Comment

by:wayan
ID: 1416697
Edited text of question
0
 
LVL 15

Accepted Solution

by:
NickRepin earned 400 total points
ID: 1416698
Here is working code:
#include <windows.h>
#include <iostream.h>
#pragma hdrstop
#include "a.rh"

BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK EnumProc(HWND, LPARAM);
static HWND hwndeng = 0;
static DWORD dwThreadId;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR lpszCmdLine, int cmdShow) {
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
return 0 ;
}

BOOL CALLBACK DlgProc(HWND hwnd, UINT mMsg, WPARAM wParam, LPARAM lParam) {
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartupInfo;
BOOL bCreate = FALSE;
siStartupInfo.cb = sizeof(STARTUPINFO);
siStartupInfo.lpReserved = NULL;
siStartupInfo.lpDesktop = NULL;
siStartupInfo.lpTitle = NULL;
siStartupInfo.dwFlags = STARTF_USESHOWWINDOW;
siStartupInfo.wShowWindow = SW_SHOWNORMAL;
siStartupInfo.cbReserved2 = 0;
siStartupInfo.lpReserved2 = NULL;

switch(mMsg) {
case WM_INITDIALOG:
bCreate = CreateProcess("calc.exe", NULL, NULL, NULL, FALSE,  
NORMAL_PRIORITY_CLASS, NULL, NULL,
&siStartupInfo,
&piProcInfo);

if(bCreate == 0) {
MessageBox(NULL, "Calc - Process Not Found",  NULL, MB_OK | MB_ICONEXCLAMATION);
return TRUE;
}

WaitForInputIdle(piProcInfo.hProcess, 3000);
dwThreadId = piProcInfo.dwThreadId;
EnumThreadWindows(dwThreadId, EnumProc, 0);

//******** Changed here (IsWindowVisible added)
// because may be top-level hidden windows (calc.exe has one)

if(hwndeng == NULL && IsWindowVisible(hwndeng)) {
MessageBox(NULL, "Calc - Enum Not Found", NULL, MB_OK | MB_ICONEXCLAMATION);
return TRUE;
}
// Can hide window here *********************
//ShowWindow(hwndeng,SW_HIDE);
// Attach input
AttachThreadInput(GetCurrentThreadId(),dwThreadId,TRUE);
return TRUE;

case WM_COMMAND:
switch(LOWORD (wParam)) {
case IDD_BUTTON1: {

// Unnecessary ?
EnableWindow(hwndeng, TRUE);

// Actually send the key
HWND oldfocus=SetFocus(hwndeng);
keybd_event(VK_F1,0x3b,0,0);
SetFocus(oldfocus);

//PostMessage(hwndeng,  WM_KEYDOWN, VK_F1, MAKELPARAM(1,0x3b));
return TRUE;
}
case IDOK:
case IDCANCEL:
CloseHandle(piProcInfo.hThread); // MUST BE CLOSED
CloseHandle(piProcInfo.hProcess);
ExitProcess(0);
EndDialog(hwnd, 0);
return TRUE;

case WM_KEYDOWN: {
  MessageBeep(-1);
  char buf[100];
  wsprintf(buf,"%X %X",wParam,lParam);
  MessageBox(0,buf,buf,MB_OK);
  break;  
}  
}
break;
}
return FALSE;
}

BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lp) {
if(GetParent(hwnd) == NULL) {
hwndeng = hwnd;
return FALSE;
}
else return TRUE;
}
0
 
LVL 15

Expert Comment

by:NickRepin
ID: 1416699
If calc.exe is written by you, I thing it's much more easy to send WM_COMMAND rather than keybd events.
0
Veeam Task Manager for Hyper-V

Task Manager for Hyper-V provides critical information that allows you to monitor Hyper-V performance by displaying real-time views of CPU and memory at the individual VM-level, so you can quickly identify which VMs are using host resources.

 

Author Comment

by:wayan
ID: 1416700
Hi, NickRepin

Your code works fine, excellent answer.

Could you please add a comment on the following:

1) This commented out code.
//PostMessage(hwndeng,  WM_KEYDOWN, VK_F1, MAKELPARAM(1,0x3b));

2) If calc.exe is written by you, I thing it's much more easy to send WM_COMMAND rather than keybd events.

I am working with ketut on this project and he was getting low on points --- Yes calc.exe (source) is in the public domain and has been extensively modified by us, and we wish to use a subset of it's functions and to completely integrate it into our GUI would take us a long time and effort.

What we want to do is invoke actions via menu accellerator strings like: Alt S, Alt Q, Alt Z etc.

As you know if you were doing this from the Keyboard, the Alt key would be depressed and the sequence would be S, Q, Z.

So that's it in a nutshell and thank you very much for your help so far.
Wayan



0
 

Author Comment

by:wayan
ID: 1416701
Just a thought on ExitProcess(0); have we got that right ?
If you need us to pose the previous comment and this one as a seperate Question, let us know.
Thanks again

wayan
0
 

Author Comment

by:wayan
ID: 1416702
keybd_event(VK_MENU, 0x3B, 0, 0);

whats the significance of the OEM scan code 3B ???
0
 
LVL 15

Expert Comment

by:NickRepin
ID: 1416703
>1) This commented out code.
>>//PostMessage(hwndeng,  WM_KEYDOWN, VK_F1, MAKELPARAM(1,0x3b));

Don't care about this.

>2) If calc.exe is written by you, I thing it's much more easy >to send WM_COMMAND rather than keybd events.
>to do is invoke actions via menu accellerator strings like: Alt >S, Alt Q, Alt Z etc.

As you see, sending keybd messages is not so easy (as I thought too). Moreover, may be some problem here. Eg, we are doing:

   SetFocus(...);
   // Theoretically, it's possible that other app sets focus to  its window here (eg, MessageBox from Spooler) and next line will not post event to calc.exe.
   keybd_event(...)

When you use the accelerator, you assing WM_COMMAND message to key combination, right?
Inside your app, there is a code like this:

  case WM_COMMAND:
     switch(code) {
      case CMD_ALT_S:
           // do something

It would better and reliable to send this command to your app, not the keybd message:

    PostMessage(hwnd,WM_COMMAND,CMD_ALT_S,0);

This should work at 100%.


//whats the significance of the OEM scan code 3B ???
I'm not sure, but according the SDK we should supply it as the parameter. You may try do pass zero here, but it may not work.
 
 
 
   
 


0
 
LVL 15

Expert Comment

by:NickRepin
ID: 1416704
I think posting WM_CLOSE message (not the ExitProcess) is the best way to close your app.
By the way, ExitProcess terminates the calling process, and you cannot terminate any other (child) process by using it.
0
 
LVL 15

Expert Comment

by:NickRepin
ID: 1416705
When using WM_COMMAND, you need no to call AttachThreadInput or SetFocus.
0
 

Author Comment

by:wayan
ID: 1416706
thanks
0

Featured Post

Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

With most software applications trying to cater to multiple user needs nowadays, the focus is to make them as configurable as possible. For e.g., when creating Silverlight applications which will connect to WCF services, the service end point usuall…
What my article will show is if you ever had to do processing to a listbox without being able to just select all the items in it. My software Visual Studio 2008 crystal report v11 My issue was I wanted to add crystal report to a form and show…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.

670 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question