Click to See Complete Forum and Search --> : Key Pressed


samcct
March 21st, 2006, 05:46 AM
Hi,

Doea anyone know how I could do something when the user press a speific key on the keyboard? For example, when the user pressed on "shift + ctrl + E", then it will launch a local application. I suppose this is quite possible. But could anyone give me some helps how I could do this?

Thanks in advance,

Samantha

sreehari
March 21st, 2006, 06:02 AM
read more on the _Kbhit() (http://msdn2.microsoft.com/en-us/library/58w7c94c(VS.80).aspx) function

check out this thread has exactly what you are lookin for :D :thumb:
exit if a key is hit, else continue... (http://www.codeguru.com/forum/showthread.php?t=370813)

philkr
March 21st, 2006, 06:10 AM
Since this is asked in the WinAPI forum RegisterHotKey() (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/registerhotkey.asp) is probably rather what you are looking for.

golanshahar
March 21st, 2006, 06:41 AM
Another option is using ::SetWindowsHookEx() (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp) with WH_KEYBOARD.

Look at this article for more info: Hooking the Keyboard (http://www.codeguru.com/Cpp/W-P/system/keyboard/article.php/c5699/)

Cheers

samcct
March 23rd, 2006, 12:12 PM
Hi sreehari, I was looking at kbhit() and getch(). But if I am not mistaken, getch can only detect one key. What I need is maybe including more than one key (probably ctrl + 1 or shift+ctrl+1).

Any idea?

Thanks,
Sam

samcct
March 24th, 2006, 05:06 AM
Is that possible if I use SetWinEventHook and SetWindowHook (for hooking the keyboard) at the same time? In my program, I am using SetWinEventHook to hook on the event. So can I use another hook for the keyboard in one program?

Thanks,
Samantha

sreehari
March 24th, 2006, 05:20 AM
Hi sreehari, I was looking at kbhit() and getch(). But if I am not mistaken, getch can only detect one key. What I need is maybe including more than one key (probably ctrl + 1 or shift+ctrl+1).

nope ....

The keys shift, Ctrl , ALT dont have an Existance of their own.... and hence when they are entered on their own are not accepted as an char input.... you have to have another key combination to go along with that.... hence the bottom line is ctrl+1 is taken as one key input....

still if you want just try out this code....

#include<iostream>
#include<conio.h>
int main()
{
while(1)
{
char c;
c = getch();
printf("%c",c);
}
return(1);
}


i think that __kbhit() and getch should be an good enough solution for your requirements... now again that depends on what you are tryin to achieve
:thumb:

samcct
March 24th, 2006, 05:43 AM
Thanks sreehari.

Unfortunately I just realized that for my program, I already used SetWinEventHook to called my callback function when any event occurs. And now, what I intend to do is, I want to check if the key (or keys) are pressed until the next event occur.

I don't know how to do that, as I can't check the key pressed in a while loop. If I do that, then it will keep going on the loop.

Any idea, everyone?

Thanks,

Samantha

PS: I am not sure if I post in the right section. Maybe I shouldn't post it in this WinAPI forum. Sorry if so.

samcct
March 24th, 2006, 06:19 AM
Btw, I am using Visual Studio 6.0 if this matters.

Thanks,
Samantha

golanshahar
March 24th, 2006, 07:07 AM
If you want to check if key is pressed you can use the ::GetAsyncKeyState() (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/getasynckeystate.asp) api.
Can you please be more specific what is it that you are trying to do?

Cheers

samcct
March 24th, 2006, 07:17 AM
I am currently using SetWinEventHook to know the events happened, for example, if any object has been focused, or created or etc. This works fine for me now. But the next step, I have to check if a specific key (or keys) are pressed while an object is being focused until the next focus event is triggered.

I hope you see what I mean here...

Thanks,

Samantha

golanshahar
March 24th, 2006, 08:56 AM
I am currently using SetWinEventHook to know the events happened, for example, if any object has been focused, or created or etc. This works fine for me now. But the next step, I have to check if a specific key (or keys) are pressed while an object is being focused until the next focus event is triggered.

I hope you see what I mean here...

Thanks,

Samantha

Well in that case you can simply use ::GetAsyncKeyState() like I suggested above, when a focus event occurs you can ::CreateThread() that checks the if the specific key is pressed using this api. If in that loop-check (in the thread) you find out that the key was up simply set a flag and break the loop - exit the thread.

When the new focus arrives you first check that flag value to see what happened between those two focuses.

Just an idea.

Another idea is to work with keyboard hook that will send each key+ up/down state to your application and you will decide what to do between the two focuses, look at the link to article I posted above.

Cheers

samcct
March 24th, 2006, 09:25 AM
Thanks for the two suggestions, golanshahar.

As for the first one, in that loop-check, do you mean it will also work in the cases where when one event happened, the user may press the key or may not press the key?

Can I use while loop for that? If so, for case 1 where the user presses the key and then it will break the loop. If for case 2, where the user doesn't press the key between two events, then how I could break the loop?

Is there any example or links I could find for this alternative?


Thanks,

Samantha

samcct
March 24th, 2006, 09:47 AM
Hi Golanshahar

Sorry if I have asked silly questions. I am very new to programming and learning from this project, in fact.

I am trying to figure this out. I can't see the way I can break or out of the check-loop (if the key is pressed or not), if the user not pressing the key in one focus event, which this might happen most of the time.

I need to see how to slot in my existing program too (which already have the winevent hook. Can you give me some example codes?

Thanks,
Samantha

golanshahar
March 24th, 2006, 01:12 PM
Hi Golanshahar

Sorry if I have asked silly questions. I am very new to programming and learning from this project, in fact.

Its ok, that’s why there is forum so people can ask and get answers :wave:


I am trying to figure this out. I can't see the way I can break or out of the check-loop (if the key is pressed or not), if the user not pressing the key in one focus event, which this might happen most of the time.

I need to see how to slot in my existing program too (which already have the winevent hook. Can you give me some example codes?

Thanks,
Samantha

If you want to check the key state its true you must need a loop something like this:

// loop that checks 'A' key state
bool bKeyState = false;
while ( true )
{
if ( ::GetAsyncKeyState('A') )
{
// key is down
bKeyState= true;
}
else
{
// key is up
bKeyState= false;
}
::Sleep(50);
}

Now this loop should be in thread. Or you can use timer that check it each interval and then you dont need the loop:

case WM_TIMER:
{
if ( ::GetAsyncKeyState('A') )
{
// key is down
bKeyState= true;
}
else
{
// key is up
bKeyState= false;
}
}
break;


The problem with these ideas is that it uses pooling mechanism that check the key state while if you will use hook you will receive callback which is more reliable.

Hope it helps.

Cheers

samcct
March 24th, 2006, 01:12 PM
Hi Golarshahar, if for the 2nd alternative (i am stuck and keep thinking of ways to do it), that means I will be using two hooks, one for the event hook and another is the keyboard hook. Is that right?

So the checking should be in which callback function? The event callback function or the keyboard keyboard function? I already read your article about the keyboard hooking. But now I am just wondering how could I integrate both hookings.

THanks,

Samantha

golanshahar
March 24th, 2006, 01:24 PM
Hi Golarshahar, if for the 2nd alternative (i am stuck and keep thinking of ways to do it), that means I will be using two hooks, one for the event hook and another is the keyboard hook. Is that right?

So the checking should be in which callback function? The event callback function or the keyboard keyboard function? I already read your article about the keyboard hooking. But now I am just wondering how could I integrate both hookings.

THanks,

Samantha

Basically there is not relation between the two hooks the keyboard hook simply hooking the keyboard events and the WinEventHook hooks the events.
What you need to do is from the keyboard hook send each key +up/down state to your application. (Using ::SendMessage() for instance ) in that case you will get notification for each key that is pressed or released in the system into your application, now set a flag for the key you want to check state and then when you will get event notification from the event hook check the flag and based on that choose what to do ( this is up to you :D cause I don’t know what you want to do in case you figured out a key was released or pressed between two focus events )

Cheers

samcct
March 24th, 2006, 01:24 PM
I think I should explain more what I am doing on my project.

I have a setWinEventHook. So it keeps taking the events (all, including object_create, object_locationchanged, object_destroy, object_focus, etc). What I want for the end result is that: I only will want to know, when a user's tab are on a particular button, let's say "MY SYSTEM", and then he needs to press a specific key (or maybe keys, let's say - Ctrl + Shft + 1) to call out another application in the local machine (this is another part of program i need to do).

So what I am doing is, I need to filter the events only for object_focus (as when the tab is on that button, it means it is on focus), and then compare the name of that object which is on focus with my "MY SYSTEM" name. And if it is the same name (which means he is on my button), then I will need to see if the user will press on the Ctrl+Shft+1 keys or he might choose not to and continue his navigation or tab to another links.

So far, I have my hook on events working, which I know all the events happening.

Hope I explain well here. I really need helps.... :-(

Thanks,
Samantha

golanshahar
March 24th, 2006, 01:58 PM
So let me get it strait, you want to know if user pressing Ctrl+Shift+1 ?
In that case it even simpler, use hot key - register a hot key for that combination and when you will receive it you will know user pressed it.
Look at ::RegisterHotKey () (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/registerhotkey.asp)

Cheers

samcct
March 24th, 2006, 02:25 PM
So let me get it strait, you want to know if user pressing Ctrl+Shift+1 ?
In that case it even simpler, use hot key - register a hot key for that combination and when you will receive it you will know user pressed it.
Look at ::RegisterHotKey () (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/registerhotkey.asp)

Cheers

But then I need to compare with the name of the object which is currently on focus. And the focus event provides the information about that object only as it happens. I won't be able to check it back what is now on focus or I can't query it. When the user press these three keys, I need to compare what was the last object being focused. If the name of the object is "MY SYSTEM", then ok, i will do something.

I looked through that registerHotKey function too.. But i don't know how to do the last part I mentioned above.

Thanks golarshahar!

golanshahar
March 24th, 2006, 05:05 PM
But then I need to compare with the name of the object which is currently on focus. And the focus event provides the information about that object only as it happens. I won't be able to check it back what is now on focus or I can't query it. When the user press these three keys, I need to compare what was the last object being focused. If the name of the object is "MY SYSTEM", then ok, i will do something.

I looked through that registerHotKey function too.. But i don't know how to do the last part I mentioned above.

Thanks golarshahar!

Can’t you simply save the last object? Each time you get the focus notification simply save all the data you need. Then when you will get the WM_HOTKEY check what was the last object in your variable.

Cheers

samcct
March 24th, 2006, 08:15 PM
Can’t you simply save the last object? Each time you get the focus notification simply save all the data you need. Then when you will get the WM_HOTKEY check what was the last object in your variable.

Cheers

Ok. How could I not thought of that :-S
I will try on them and let you know how it goes...

Thanks,
Samantha

golanshahar
March 25th, 2006, 05:11 AM
Ok. How could I not thought of that :-S
I will try on them and let you know how it goes...

Thanks,
Samantha

Ok Samantha, Good luck :wave:

Cheers

samcct
March 25th, 2006, 07:22 AM
Hi Golanshahar,

I was looking at the examples on the Internet. I am not sure where I should put the WM_HOTKEY in the program. In all the examples, they have a dialog box and therefore have something like this:

BEGIN_MESSSAGE_MAP (CMyDialog, CDialog)
ON_MESSAGE(WM_HOTKEY, onHotKey)
END_MESSAGE_MAP

If I am not mistaken, they are written in MFC, while mine is in VC++ Win32 Application.

Where should I do this?

And also, they register their hot key in OnInitDIalog function, again, I think this is in MFC, isn't it? What about mine?

Another question, what is the different using RegisterHotKey and Hooking the keyboard (KeyboardProc, etc)?


Thanks,
Samantha

golanshahar
March 25th, 2006, 09:48 AM
Hi Golanshahar,

I was looking at the examples on the Internet. I am not sure where I should put the WM_HOTKEY in the program. In all the examples, they have a dialog box and therefore have something like this:

BEGIN_MESSSAGE_MAP (CMyDialog, CDialog)
ON_MESSAGE(WM_HOTKEY, onHotKey)
END_MESSAGE_MAP

If I am not mistaken, they are written in MFC, while mine is in VC++ Win32 Application.

Where should I do this?

In the winproc you should have one in the application where you handling events there you should put it.


And also, they register their hot key in OnInitDIalog function, again, I think this is in MFC, isn't it? What about mine?


Since you are not using MFC you should do in also in the winproc just handle the WM_INITDIALOG (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/dialogboxes/dialogboxreference/dialogboxmessages/wm_initdialog.asp)


Another question, what is the different using RegisterHotKey and Hooking the keyboard (KeyboardProc, etc)?


First of all in code length :D hooking the keyboard requires you writing a dll and then you have to implement another IPC mechanism in order to send the data from the dll to your application since the dll is injected to all other processes. While using ::RegisterHotKey() is much more simple and of course less coding :D all you have to do is register the key and then wait for the WM_HOTKEY message.

Basically when you using the ::RegisterHotKey() you are letting windows to do all the decisions what/when the hotkey was pressed, while in hooking you need to do all the logics by yourself.

Obviously there are more things I can’t think of them at the moment.

Cheers

samcct
March 25th, 2006, 09:59 AM
Hi Golanshahar,

So let's say I have something like this:

LRESULT CALLBACK
MainWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch( uMsg )
{
case WM_CREATE:
{
}
break;
case WM_HOTKEY:
{
onHotKey (WPARAM wparam, LPARAM lparam);
}
break;
}
}

But there are errors for this :-( What I have missed here?

You mentioned about "do in also in the winproc just handle the WM_INITDIALOG ", I don't get you on this point.... Could you explain more on this, please?

Thanks for your patience!

Samantha

golanshahar
March 25th, 2006, 11:12 AM
what i meant was this:

LRESULT CALLBACK MainWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch( uMsg )
{
case WM_CREATE:
{

}
break;
case WM_HOTKEY:
{
// Here hot key notification arrived choose what to do
}
break;
case WM_INITDIALOG:
{
//call ::Registerhotkey(); here
}
break;
}
}



BTW what is onHotKey (WPARAM wparam, LPARAM lparam); ?
if you implemented this function you should call it like this:

onHotKey (wParam, lParam);


Cheers

samcct
March 25th, 2006, 11:58 AM
Thanks Golanshahar... I got what you mean there and it works ok for this now. Thanks a lot.

But I am having another problem, which might not related exactly with this problem. As I mentioned in the previous post, I got to save the last focus event and now I need to compare the name of the object (which is focused at that moment) with my "MY SYSTEM".

The thing is, in my program, there are two files: let's say: file 1 and file 2.
The last event is saved as the global variable - BSTR storage in one of the .cpp file in file 2 (let's say, event.cpp).

Now my onHotKey function, which I have it in the

case WM_HOTKEY {
onHotKey (wparam, lparam)
}

it is in file 1 (let's say, main.cpp). How could I compare "MY SYSTEM" with "storage" in this file (main.cpp) in file 1?

LRESULT onHotKey (WPARAM wparam, LPARAM lparam)
{
if (wcscmp (storage, L"ENABLED SYSTEM") == 0)
{
MessageBox(NULL, "ALL DONE", "OK",0);
} else {
MessageBox(NULL, "NOT DONE YET", "FAIL", 0);
}
}

I think this is more on programming rules, which I might still need to learn. Do you have any idea how I could do that?

Thanks,

Samantha

golanshahar
March 25th, 2006, 01:26 PM
you can use the extern keyword:


File1.cpp
int Variable =0;



File2.cpp
where you want to check the value of Variable which is declared in File1.cpp

extern int Variable;


thats it ;)

Cheers

samcct
March 25th, 2006, 01:37 PM
you can use the extern keyword:


File1.cpp
int Variable =0;



File2.cpp
where you want to check the value of Variable which is declared in File1.cpp

extern int Variable;


thats it ;)

Cheers

Hi Golanshahar, once I add the extern on my variable:

extern BSTR storage;

it comes up with 2 errors:

objects.obj : error LNK2001: unresolved external symbol "unsigned short * storage" (?storage@@3PAGA)
..\binfiles\x86_unicode_debug/event.dll : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

What's wrong with it? :-(

samcct
March 25th, 2006, 01:40 PM
Is that because my variable is not an int but it is a BSTR?

samcct
March 25th, 2006, 01:45 PM
Yeah, I just tried with extern int store, and it doesn't have any error.

What else I can do if mine is not a int, but it is BSTR? THe focus event's name and value is in BSTR... That's why when I comparing, I am using
if (wcscmp (storage, L"MY SYSTEM") == 0)

with BSTR storage.

Please help...... :-(

golanshahar
March 25th, 2006, 02:27 PM
Yeah, I just tried with extern int store, and it doesn't have any error.

What else I can do if mine is not a int, but it is BSTR? THe focus event's name and value is in BSTR... That's why when I comparing, I am using
if (wcscmp (storage, L"MY SYSTEM") == 0)

with BSTR storage.

Please help...... :-(

No. it doesn’t matter what type of variable you are using! extern is extern.
:confused:
probably there is something else there, Post the code you are using.

Cheers

samcct
March 25th, 2006, 02:44 PM
Hi Golanshahar,

I meant to tell you that I have 2 projects. Project 1 and 2. ( This is an example I found and I took it as a referecence)

Project 1: File 1
Project 2: File 2
File 3

<<<<File 1>>>>

BSTR storage;

LRESULT OnHotKey (WPARAM wparam, LPARAM lparam)
{
if (wcscmp (storage, L"ENABLED SYSTEM") == 0)
{
ShellExecute(hwndMain, LPCTSTR("open"), LPCTSTR("C:\\mySystem.exe"), NULL, NULL, SW_SHOW);
} else {
MessageBox(NULL, L"NOT DONE YET", L"OK", 0);
}
return 0;
}

<<<<File 2 - callback from SetWinEventProc>>>>

void CALLBACK NotifyProc
(
HWINEVENTHOOK hEvent,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD idThread,
DWORD dwEventTime
)
{ ObjectProc( evParams, EventText );
}


<<<<File 3 (which I declare my extern)>>>>

extern BSTR storage;

void WINAPI ObjectProc( const EventParams & evParams,
StrWrPos & EvText )
{
GetObjProp_GenericStr( pAcc, pvarChild, str, & IAccessible::get_accName, DISPID_ACC_NAME );
}

void GetObjProp_GenericStr( IAccessible * pAcc, VARIANT * pvarChild, StrWrPos & str, PMTH_IAccGetStr pmthGetStrProp, DISPID DispID )
{
BSTR bstrName;
bstrName = NULL

if( SUCCEEDED( hr ) && bstrName )
{
str << TEXT("\"") << bstrName << TEXT("\"");
storage = bstrName;

if( bstrName[0] != '\0' )
{
AddedText = TRUE;
}

SysFreeString( bstrName );
}
}

I know it's very complicated. The codes is link to many other part of program, but basically this is the related part.

Thanks,

Samantha

golanshahar
March 25th, 2006, 03:30 PM
What is the relation between the two projects?

Plus could you attach the whole projects? It will be easier to find out what is going on.

Cheers

samcct
March 25th, 2006, 04:35 PM
Hi Golanshahar,

As I said before, I refer this from an example of MSAA by Microsoft. It is quite complicated. Hope you don't mind having a look on it.


THanks,
Samantha

samcct
March 25th, 2006, 04:40 PM
Basically the few main files are: accevent.cpp, event.cpp and objects.cpp.

This is MSAA-based. Basically to know the events but I modified it so that it only read focus event. And to final objective for me is to know when the user is on a specific button. If they press the shift+E button when the focus is on that button (I assume the user uses tab key to navigate all the buttons and links on the webpage as this project is for visually impaired users). If they do press the keys when the focus is on that button, then I will launch my another application.

Maybe it's easy for most of the people, but so annoyed I have been stucked on this for nearly a month.... :-(

THanks,

Samantha

golanshahar
March 25th, 2006, 06:12 PM
You cant use extern in your case since you have two projects there one is an exe the other one is a dll.
What you can do is create an exported function from the dll so you will be able to call it form the exe and then it will update a global variable in the dll.

Cheers

samcct
March 25th, 2006, 06:28 PM
You cant use extern in your case since you have two projects there one is an exe the other one is a dll.
What you can do is create an exported function from the dll so you will be able to call it form the exe and then it will update a global variable in the dll.

Cheers

Hi Golanshahar,

Can you describe more about the way I can sort this out? What do you mean creating an exported function from the dll? Which dll you are referring to? I am totally lost.... :-(

Please could you give me some example or explain to me in more detail?

Really appreciate you helps... I am really lost now...

Thanks,

golanshahar
March 26th, 2006, 02:45 AM
Hi Golanshahar,

Can you describe more about the way I can sort this out? What do you mean creating an exported function from the dll? Which dll you are referring to? I am totally lost.... :-(

Please could you give me some example or explain to me in more detail?

Really appreciate you helps... I am really lost now...

Thanks,

You shouldn’t be lost, you should know what kind of sources/projects you are dealing with!

You got an exe file and an event.dll file this is what you posted.
So since you want to update the BSTR variable from the exe in the dll you need to communicate between the two..how? By using function that the dll will export so the exe could call it. (Its basic things about dlls you can read the MSDN for that)
You can also look at this FAQ (http://www.codeguru.com/forum/showthread.php?t=231254). ;)

Cheers

samcct
March 26th, 2006, 07:41 AM
I getting more understand about dll and exported function. But I am trying to know which file is the dll file which I could add my exported function in. I couldn't find any export function in any of the files in the second project, which is the dll.

I suppose I have to declare the function which I use my variable (BSTR storage) as the global variable. Am I right? So that it can be called and used in exe file. But there are loads of files in the 2nd project which I believe is the dll. I would say there must be some exported function declared before but odd that I couldn't find anything like "export" or "'__declspec(dllexport)'" or "__stdcall".

Sorry for being totally lost. I was too streesed last night after the whole day working but still can't figure things out.... Programming is really a new area for me and yet the first project seems to be too complicated for me and the deadline is approaching.

Thanks,
S.

golanshahar
March 26th, 2006, 11:18 AM
I getting more understand about dll and exported function. But I am trying to know which file is the dll file which I could add my exported function in. I couldn't find any export function in any of the files in the second project, which is the dll.

I suppose I have to declare the function which I use my variable (BSTR storage) as the global variable. Am I right? So that it can be called and used in exe file. But there are loads of files in the 2nd project which I believe is the dll. I would say there must be some exported function declared before but odd that I couldn't find anything like "export" or "'__declspec(dllexport)'" or "__stdcall".

Sorry for being totally lost. I was too streesed last night after the whole day working but still can't figure things out.... Programming is really a new area for me and yet the first project seems to be too complicated for me and the deadline is approaching.

Thanks,
S.

Reading the MSDN shows that the hmodWinEventProc param of ::SetWinEventHook() should be in dll:

hmodWinEventProc
[in] Handle to the dynamic-link library (DLL) that contains the hook function at lpfnWinEventProc if the WINEVENT_INCONTEXT flag is specified in the dwFlags parameter. If the hook function is not located in a DLL, or if the WINEVENT_OUTOFCONTEXT flag is specified, this parameter is NULL.

That is why there are no exported functions there!

Looks like exported function wont help in a case where this dll is being injected to other processes.
One thing you can try is using shared memory between the exe and dll, look at this thread for more info DLL's Memory ( http://www.codeguru.com/forum/showthread.php?t=347467)

PS: why did you remove the project from the other post? :confused: )

TIP: as i understood you took a sample from MS and use it in your code, copying and pasting code wont help you understand programming, you should be able at least to understand what the pasted code doing. Either by reading the help (MSDN) on the API functions or reading a book about the issue.

Cheers

samcct
March 26th, 2006, 12:17 PM
Reading the MSDN shows that the hmodWinEventProc param of ::SetWinEventHook() should be in dll:

That is why there are no exported functions there!

Looks like exported function wont help in a case where this dll is being injected to other processes.
One thing you can try is using shared memory between the exe and dll, look at this thread for more info DLL's Memory ( http://www.codeguru.com/forum/showthread.php?t=347467)

PS: why did you remove the project from the other post? :confused: )

TIP: as i understood you took a sample from MS and use it in your code, copying and pasting code wont help you understand programming, you should be able at least to understand what the pasted code doing. Either by reading the help (MSDN) on the API functions or reading a book about the issue.

Cheers


oh no.... so for my case, the SetWinEventHook is in the exe. That's why it is not going to work if I use the export method to get my last event in dll to use it in the exe?

I was thinking is there any other ways I can do for my case so that I can reach my final aim - to know if the user presses they key when they are on that button....

Thanks for your tips. I know this is not a good way of learning especially try to understand others' code. I am indeed trying to understand the codes and in fact I was already work on this code for two weeks just to understand part of it. I might be slow, as there are a lot of issues involve in the whole workspace. When I found a new issue, I go into it and learn about it. Just like this dll, I just found it is working as dll, so i was spending the whole day today looking at this area.

I will attach the project in this post again, which can be compile without errors. THe previous one contains some errors, as last night everything seems to be went wrong.

Could you possible thought of any other way I can try for my case? The concept seems to be so simple (just to see if the user presses the button when the focus is on the specific button). I was expected to finish this very soon, as they thought the concept is so simple and thus I should finish very quick and easy.... Don't know if it's me that I am slow in learning, or it is indeed a bit complicated.... :-(

Thanks, really for your helps..

Samantha

golanshahar
March 26th, 2006, 04:27 PM
Ok then since you are in really bad situation there and I feel for you, here is some help that should get you back on the track I modified two files in your project the first one is the event.cpp in the dll.
in the:

void CALLBACK
NotifyProc
(
HWINEVENTHOOK hEvent,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD idThread,
DWORD dwEventTime
)

What I did was sending from that callback a BSTR string to the EXE file using WM_COPYDATA...you should add the correct string you want to pass to the application ( I don’t know what you want to send so I send just a test string)

Now in the EXE the file accevent.cpp I added the handling to WM_COPYDATA in order to get the BSTR from the dll.

All you have to do here is just send the correct BSTR to the EXE (change my test text) and in the EXE store if in a global variable for future use.

This should HELP you....its almost 99% of what you need.

Look at the attached project.

Cheers

samcct
March 26th, 2006, 05:56 PM
Thanks Golanshahar!!! Thanks for willing to help, really.

I was looking at the code you added and finding out how they work.

What I want to sent is the BSTR bstrName of the last event. It is in objects.cpp in event files project (the dll). So could I put the code you added in event.cpp to objects.cpp? As far as I understand, these codes are trying to pass the string ("BSTR storage" for my case) into a new allocated string and send it as a message (in WM_COPYDATA). Am I right? So I changed it into this:

BSTR bstr = ::SysAllocString(storage);
COPYDATASTRUCT cd={0};
cd.lpData = bstr;
cd.cbData = ::SysStringLen(bstr);
::SendMessage (hApp,WM_COPYDATA,0,(LPARAM)&cd);
::SysFreeString(bstr)

and I put the whole bunch of codes in the GetObjProp_GenericStr function in objects.cpp. Not sure if this is right though according to my logic (which might be wrong).
-----------------------------------------------------
Whereas in accevent.cpp,

case WM_HOTKEY:
{
onHotKey (wparam, lparam);
}
break;
case WM_COPYDATA:
{
COPYDATASTRUCT *cd = (COPYDATASTRUCT*)lParam;
BSTR lastMessage = ::SysAllocString((unsigned short*)cd->lpData);
SysFreeString(lastMessage);
}

I undestand this as - allocating another string and retrieve the "BSTR storage" we saved.
Also in accevent.cpp as well, I have this function to compare the last event's name with my button name

LRESULT onHotKey (WPARAM wparam, LPARAM lparam)
{
if (wcscmp (lastMessage, L"MY SYSTEM") == 0)
{
ShellExecuteW(hwndMain, L"open", L"C:\\mysystem.exe", NULL, NULL, SW_SHOW);
} else {
MessageBox(NULL, L"NOT EXECUTING", L"NO", 0);
}
return 0;
}

where on the top of accevent.cpp, I define

BSTR lastMessage;
--------------------------------------------------

It seems to compile ok, but whenever I press the keys no matter it is on the button or not, it will pop up an error message saying that the Accessibility tester encounter a problem and have to close down.

My apologies if I have been asking too much and thanks, indeed for being so kind and considerate. I will keep looking on the codes and try to understand more..

Thanks again,
Samantha

samcct
March 26th, 2006, 06:18 PM
Hi Golanshahar,

Sorry... another thing, I was looking at the codes you added in event.cpp:

HWND hApp = ::FindWindow(0,L"ENABLED EXPLORER");
if ( hApp )
{
BSTR bstr = ::SysAllocString(L"Hello from dll");
COPYDATASTRUCT cd={0};
cd.lpData = bstr;
cd.cbData = ::SysStringLen(bstr);
::SendMessage (hApp,WM_COPYDATA,0,(LPARAM)&cd);
::SysFreeString(bstr);

}

I am not sure if it is alright to write as in the first line. Because if it is that case, it will only compare for webpage with this name. For my case, I won't know what is the window name, as this will depend on the other web developer to put the name for their webpages. Actually we intend to have the help of web developers to add a button called let's say "MY EXPLORER" if they want to use our system. SO the window name will be varied.

So I changed it as follow:

HWND hApp = ::FindWindow(L"IEFrame", 0);

but still place the whole bunch of code in GetObjProp_GenericStr function in objects.cpp. Still the same errors..

golanshahar
March 27th, 2006, 03:58 AM
Thanks Golanshahar!!! Thanks for willing to help, really.

I was looking at the code you added and finding out how they work.

What I want to sent is the BSTR bstrName of the last event. It is in objects.cpp in event files project (the dll). So could I put the code you added in event.cpp to objects.cpp? As far as I understand, these codes are trying to pass the string ("BSTR storage" for my case) into a new allocated string and send it as a message (in WM_COPYDATA). Am I right? So I changed it into this:

BSTR bstr = ::SysAllocString(storage);
COPYDATASTRUCT cd={0};
cd.lpData = bstr;
cd.cbData = ::SysStringLen(bstr);
::SendMessage (hApp,WM_COPYDATA,0,(LPARAM)&cd);
::SysFreeString(bstr)

and I put the whole bunch of codes in the GetObjProp_GenericStr function in objects.cpp. Not sure if this is right though according to my logic (which might be wrong).
-----------------------------------------------------
Whereas in accevent.cpp,

case WM_HOTKEY:
{
onHotKey (wparam, lparam);
}
break;
case WM_COPYDATA:
{
COPYDATASTRUCT *cd = (COPYDATASTRUCT*)lParam;
BSTR lastMessage = ::SysAllocString((unsigned short*)cd->lpData);
SysFreeString(lastMessage);
}

I undestand this as - allocating another string and retrieve the "BSTR storage" we saved.
Also in accevent.cpp as well, I have this function to compare the last event's name with my button name

LRESULT onHotKey (WPARAM wparam, LPARAM lparam)
{
if (wcscmp (lastMessage, L"MY SYSTEM") == 0)
{
ShellExecuteW(hwndMain, L"open", L"C:\\mysystem.exe", NULL, NULL, SW_SHOW);
} else {
MessageBox(NULL, L"NOT EXECUTING", L"NO", 0);
}
return 0;
}

where on the top of accevent.cpp, I define

BSTR lastMessage;
--------------------------------------------------

It seems to compile ok, but whenever I press the keys no matter it is on the button or not, it will pop up an error message saying that the Accessibility tester encounter a problem and have to close down.

My apologies if I have been asking too much and thanks, indeed for being so kind and considerate. I will keep looking on the codes and try to understand more..

Thanks again,
Samantha

First since you already have the storage as bstr you don’t need to alloc it simply send it as is:


COPYDATASTRUCT cd={0};
cd.lpData = storage;
cd.cbData = ::SysStringLen(storage);
::SendMessage (hApp,WM_COPYDATA,0,(LPARAM)&cd);


Now in the receiving side you have a bug:

COPYDATASTRUCT *cd = (COPYDATASTRUCT*)lParam;
BSTR lastMessage = ::SysAllocString((unsigned short*)cd->lpData);
SysFreeString(lastMessage);

you declaring the lastMessage as local variable and then you freeing the string! You should save it (you said it yourself in the other posts) so it has to be declared as global and you need set the value to the global variable, just before setting the value make sure to call ::SysFreeString() ( if you already used ::SysAllocString() so you wont leak memory.

Cheers

golanshahar
March 27th, 2006, 04:13 AM
Hi Golanshahar,

Sorry... another thing, I was looking at the codes you added in event.cpp:

HWND hApp = ::FindWindow(0,L"ENABLED EXPLORER");
if ( hApp )
{
BSTR bstr = ::SysAllocString(L"Hello from dll");
COPYDATASTRUCT cd={0};
cd.lpData = bstr;
cd.cbData = ::SysStringLen(bstr);
::SendMessage (hApp,WM_COPYDATA,0,(LPARAM)&cd);
::SysFreeString(bstr);

}

I am not sure if it is alright to write as in the first line. Because if it is that case, it will only compare for webpage with this name. For my case, I won't know what is the window name, as this will depend on the other web developer to put the name for their webpages. Actually we intend to have the help of web developers to add a button called let's say "MY EXPLORER" if they want to use our system. SO the window name will be varied.

So I changed it as follow:

HWND hApp = ::FindWindow(L"IEFrame", 0);

but still place the whole bunch of code in GetObjProp_GenericStr function in objects.cpp. Still the same errors..

Samantha, you didn’t understand the code, i am using ::FindWindow() to locate the EXE file of yours in order to get a handle to the window so i can pass the WM_COPYDATA message. Now since the caption of your exe file is ENABLED EXPLORER this is what i used. If you will ever change it you will need to change the code too.

Finding the IEFrame window will send the WM_COPYDATA to the Internet explorer window this is defiantly not what you want.

Cheers

samcct
March 27th, 2006, 04:26 AM
Now in the receiving side you have a bug:

COPYDATASTRUCT *cd = (COPYDATASTRUCT*)lParam;
BSTR lastMessage = ::SysAllocString((unsigned short*)cd->lpData);
SysFreeString(lastMessage);

you declaring the lastMessage as local variable and then you freeing the string! You should save it (you said it yourself in the other posts) so it has to be declared as global and you need set the value to the global variable, just before setting the value make sure to call ::SysFreeString() ( if you already used ::SysAllocString() so you wont leak memory.

Cheers

Hi Golanshahar,

If I am not mistaken and from the examples I found from the Internet about declaring global variable, this is one of the way where I declare BSTR lastMessage at the very top of the accevent.cpp (if this is right, I already done this).

I think what I was wrong before is adding BSTR again in front of the lastMessage in case WM_COPYDATA. So it becomes:

COPYDATASTRUCT *cd = ( COPYDATASTRUCT*)lParam;
lastMessage= ::SysAllocString((unsigned short*)cd->lpData);
::SysFreeString(lastMessage);

Is this the right way?
It seems to be fine now, but since I have the onHotKey function as follow:

LRESULT onHotKey (WPARAM wparam, LPARAM lparam)
{
if (wcscmp (lastMessage, L"ENABLED SYSTEM") == 0)
{
ShellExecuteW(hwndMain, L"open", L"C:\\enabled.exe", NULL, NULL, SW_SHOW);
} else {
MessageBox(NULL, L"NOT EXECUTING", L"NO", 0);
}
return 0;
}

it will always go to "NOT EXECUTING" though the last event name is the same as mine (the user presses to button).
Thanks,
Samantha

PS: Apparently I can't rate your posts in this thread more than once???!!

samcct
March 27th, 2006, 05:14 AM
Samantha, you didn’t understand the code, i am using ::FindWindow() to locate the EXE file of yours in order to get a handle to the window so i can pass the WM_COPYDATA message. Now since the caption of your exe file is ENABLED EXPLORER this is what i used. If you will ever change it you will need to change the code too.

Finding the IEFrame window will send the WM_COPYDATA to the Internet explorer window this is defiantly not what you want.

Cheers

Sorry... I got you now :-( Before I use this methodology, I was trying on another approach, and from what I used before (and from examples), it somehow makes me understood it as - finding a window (IEFrame) and then use SetWinEventHook to hook on the events happened on that window. From there, all the objects on that window can be accessed.

But now after you explained, I see how it can be works in this way. Ugghh... I should think and interprete things in more ways... sorry about that, really.

Thanks indeed... Samantha

samcct
March 27th, 2006, 06:57 AM
Now in the receiving side you have a bug:

COPYDATASTRUCT *cd = (COPYDATASTRUCT*)lParam;
BSTR lastMessage = ::SysAllocString((unsigned short*)cd->lpData);
SysFreeString(lastMessage);

you declaring the lastMessage as local variable and then you freeing the string! You should save it (you said it yourself in the other posts) so it has to be declared as global and you need set the value to the global variable, just before setting the value make sure to call ::SysFreeString() ( if you already used ::SysAllocString() so you wont leak memory.

Cheers

I am thinking I might missed something out here. You said I should declare the lastMessage as global (I did this by having it on the top of the file). And, you said "I need to set the value to the global variable". I am not sure about this part. I thought the

BSTR lastMessage = ::SysAllocString((unsigned short*)cd->lpData);

already set the value of lastMessage. No?

And also, you said "Just before setting the value, makes sure to call ::SysFreeString() if I already used ::SysAllocString()".
I was looking through msdn, they mentioned about this. Ummm... So you mean I have to call ::SysFreeString(), then I can set the value? But in the code you added in my codes, you mentioned it in another way.

// Get the bstr from that was sended from the dll
COPYDATASTRUCT *cd = ( COPYDATASTRUCT*)lParam;
lastMessage = ::SysAllocString((unsigned short*)cd->lpData);
/// save thr bSTR here
::SysFreeString(lastMessage);

As I don't understand how to set the value as I mentioned above, I am not sure which way is right...

And also, I read the msdn, it calls sysFreeString before sysAllocString:

<<MSDN>>

inline void CStatBar::SetText(OLECHAR * sz)
{
SysFreeString(m_bstrMsg); // Free previous string, if any.
m_bstrMsg = SysAllocString(sz);
// Caller should check to see if m_bstrMsg is null after calling this method.
}

I know I still missed something out, that's why the lastMessage is still not the storage value, and thus it always show that nothing is the same as my button name.

Thanks,
Samantha

golanshahar
March 27th, 2006, 09:15 AM
I am thinking I might missed something out here. You said I should declare the lastMessage as global (I did this by having it on the top of the file). And, you said "I need to set the value to the global variable". I am not sure about this part. I thought the

BSTR lastMessage = ::SysAllocString((unsigned short*)cd->lpData);

already set the value of lastMessage. No?

Well you declaring a local variable BSTR lastMessage it wont set the global one. If you have a global one your code should look like this:
lastMessage = ::SysAllocString((unsigned short*)cd->lpData);



And also, you said "Just before setting the value, makes sure to call ::SysFreeString() if I already used ::SysAllocString()".
I was looking through msdn, they mentioned about this. Ummm... So you mean I have to call ::SysFreeString(), then I can set the value? But in the code you added in my codes, you mentioned it in another way.

// Get the bstr from that was sended from the dll
COPYDATASTRUCT *cd = ( COPYDATASTRUCT*)lParam;
lastMessage = ::SysAllocString((unsigned short*)cd->lpData);
/// save thr bSTR here
::SysFreeString(lastMessage);


IF you using global variable, then before each set if is not empty (because of the last call) you should free the string otherwise you code will leak memory.

PS: my code was just a sample of how to send the bstr from the dll to the exe...in my code i declared local variable both on the sender side and on the receiver side, since you have to save the data you should use global variables on both sides (EXE/DLL )

Cheers

samcct
March 27th, 2006, 09:24 AM
Well you declaring a local variable BSTR lastMessage it wont set the global one. If you have a global one your code should look like this:
lastMessage = ::SysAllocString((unsigned short*)cd->lpData);


IF you using global variable, then before each set if is not empty (because of the last call) you should free the string otherwise you code will leak memory.

PS: my code was just a sample of how to send the bstr from the dll to the exe...in my code i declared local variable both on the sender side and on the receiver side, since you have to save the data you should use global variables on both sides (EXE/DLL )

Cheers

Sorry I missed type on the post. I already have BSTR lastMessage on the top of the file (i presume this is how I use globle variable). And yes, I indeed already have code like this when I posted to you.

<<in exe>>
COPYDATASTRUCT *cd = ( COPYDATASTRUCT*)lParam;
lastMessage = ::SysAllocString((unsigned short*)cd->lpData);
::SysFreeString(lastMessage);

Is this suppose to working now? Or I still missed out something else?

<<in dll>> at the top I have BSTR storage

HWND hApp = ::FindWindow(0,L"ENABLED EXPLORER");
if ( hApp )
{
COPYDATASTRUCT cd={0};
cd.lpData = storage;
cd.cbData = ::SysStringLen(storage);
::SendMessage (hApp,WM_COPYDATA,0,(LPARAM)&cd);
::SysFreeString(storage);
}


I still have the problem where whenever I press the keys either the focus is one the button or not, it still will say no matching.

If this is the right way to call the variables in both sides, then I suppose the problem might be in another part.

Thanks a lot,

golanshahar
March 27th, 2006, 10:26 AM
Sorry I missed type on the post. I already have BSTR lastMessage on the top of the file (i presume this is how I use globle variable). And yes, I indeed already have code like this when I posted to you.

<<in exe>>
COPYDATASTRUCT *cd = ( COPYDATASTRUCT*)lParam;
lastMessage = ::SysAllocString((unsigned short*)cd->lpData);
::SysFreeString(lastMessage);

Is this suppose to working now? Or I still missed out something else?

<<in dll>> at the top I have BSTR storage

HWND hApp = ::FindWindow(0,L"ENABLED EXPLORER");
if ( hApp )
{
COPYDATASTRUCT cd={0};
cd.lpData = storage;
cd.cbData = ::SysStringLen(storage);
::SendMessage (hApp,WM_COPYDATA,0,(LPARAM)&cd);
::SysFreeString(storage);
}


I still have the problem where whenever I press the keys either the focus is one the button or not, it still will say no matching.

If this is the right way to call the variables in both sides, then I suppose the problem might be in another part.

Thanks a lot,


No :eek:
What i meant was instead of this:

COPYDATASTRUCT *cd = ( COPYDATASTRUCT*)lParam;
lastMessage = ::SysAllocString((unsigned short*)cd->lpData);
::SysFreeString(lastMessage);


Is this:

COPYDATASTRUCT *cd = ( COPYDATASTRUCT*)lParam;
if ( lastMessage!=0 && ::SysStringLen(lastMessage )>0 )
::SysFreeString(lastMessage);
lastMessage = ::SysAllocString((unsigned short*)cd->lpData);

Look at my posts: BEFORE setting the global var check if there is something in the global if so release it and then set the data so you wont cause a leak.

Cheers

samcct
March 27th, 2006, 10:44 AM
No :eek:
What i meant was instead of this:

COPYDATASTRUCT *cd = ( COPYDATASTRUCT*)lParam;
lastMessage = ::SysAllocString((unsigned short*)cd->lpData);
::SysFreeString(lastMessage);


Is this:

COPYDATASTRUCT *cd = ( COPYDATASTRUCT*)lParam;
if ( lastMessage!=0 && ::SysStringLen(lastMessage )>0 )
::SysFreeString(lastMessage);
lastMessage = ::SysAllocString((unsigned short*)cd->lpData);

Look at my posts: BEFORE setting the global var check if there is something in the global if so release it and then set the data so you wont cause a leak.

Cheers

I did try this before, having ::SysFreeString(lastMessage) before SysAllocString, as you suggested and mentioned in msdn. But it doesn't work as well. That's why I thought it's wrong. :-( (although I didn't have the checking).

Whenever I run the program and press the keys, it will come out a error box
**********************************
ENABLED EXPLORER: accevent.exe - Application Error

The instruction at "0x00402250" referecened memory at "0x00000000". The memory could not be "read". Click on OK to terminate the program. Click on CANCEL to debug the program.
**********************************

In another case where there is a window focused, no matter where I press the keys, it will always show no matching. Can you advise where I get wrong again?

Many Thanks,

golanshahar
March 27th, 2006, 12:43 PM
So.......run the application in debug mode - click Cancel and see where/why it happens...maybe you working on NULL string...but there is no room for guessing if the debugger will show you the answer for the crash.

Cheers

samcct
March 27th, 2006, 01:01 PM
So.......run the application in debug mode - click Cancel and see where/why it happens...maybe you working on NULL string...but there is no room for guessing if the debugger will show you the answer for the crash.

Cheers

:-( I tried to debug this earlier on, before I posted the previous post. Then it just hang there and I have to reboot my machine... As you suggested, so I did this again, I clicked on the CANCEL button, and then it pops up a window "Just-In-Time Debugging". Then it just hang there and I can't click on anything and nothing I can do after that, apart from rebooting my machine.... :-(

There are two cases:
1. After I run the program, it shows me my window. Then I straight away press the keys, it will then pop up the error window as I mentioned earlier.

2. After I run the program, it shows me my window. Then I click on any window (eg. IE window), then I press the keys, it shows me the message box which I place when the name is not the same as my button name. This always happen even though I am actually on that button.

Any other ways I can trace what is the wrong part? It should be reading my lastMessage, isn't it? Grrrrr....

Thanks,

samcct
March 27th, 2006, 03:27 PM
Hi golanshahar, I came back to my house and use my own machine (XP) and instead of having that error box, it has a window called "Active Accessibility event Tester (Unicode - Debug). It asks me if I want to tell MS about this problem. THen I click on the Debug button, it will try to debug and the have another boc: event queue handler window:accevent.exe - application error. I have only one choice - click ok to terminate program.

Another machine I was running this afternoon is Windows 2000.

Do you have any clue what this about? Do you mind if I post my latest program and try to run it and presses the shift+E button?

Sorry to bother you... I don't understnad why it just doesn't go smooth as I wish... I knew some problems will occur once one solved :-( No luck on me...

Thanks,
Samantha

golanshahar
March 27th, 2006, 04:34 PM
I have no problem fixing the problem in your application however I don’t think its ok, you should be able to track the bug yourself! It should be very simple there were couple of spots where you added code.

in the dll for sending the message
in the Exe for getting the message
maybe other place when you try to check the data on that BSTR.


Start debugging the application, either by using ::OutputDebugString() (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/outputdebugstring.asp) or even more simple you can comment some lines from the new added code till you find out which line is causing the crash! Or even putting breakpoints at those places and see what happens, there are a lot of methods to do it.

Debugging application is something you should do by yourself, when you will find the bug or the line that causes the crash I am pretty sure you will understand why, if not simply ask.

I am sorry if it sounds like I don’t want to help, I just think that in that way I am helping you more.

Cheers

samcct
March 27th, 2006, 05:07 PM
Ok golanshahar. I understand that. I know I should do so (just become stress and nervous from day to day...) but yeah, i will try it myself.

I think I will start of with debugging with outputDebugString. But one question which I meant to ask for long time:

I know I can use OutputDebugString to output a specific string, eg:

::OutputDebugString(L"This is a test");

but how could I use it to output a variable, eg the lastMessage? I can't write it like this....
::OutputDebugString(lastMessage);
so how could I do that? I meant to find this out for OutputDebugString and MessageBox too....

Thanks,

golanshahar
March 27th, 2006, 05:16 PM
:) ok then.

You can use _bstr_t to convert BSTR to char* look at this little sample:

// decalre some BSTR
BSTR bstr = ::SysAllocString(L"hello world");

_bstr_t strTmp ( bstr);
::OutputDebugString(strTmp);

// free the tmp BSTR
::SysFreeString(bstr);



just dont forget to:

#include <comdef.h>


Cheers

samcct
March 27th, 2006, 06:15 PM
I don't get it, golanshahar..... :-( :-( :-(

1. I put OutputDebugString in WM_HOTKEY, it printed ok. But I put it anywhere in objects.cpp... it doesn't print out anything in the debug box. Do you have any idea why it is?

2. I think the problem is the storage and lastMessage. In the accevent.cpp, whenever I add in the comparison, it will hang when I press the key without any new window, and I have to reboot. I had been rebooting my machine for 6th times today (twice since I start debuggin)... not good! I have to take away te comparison of lastMessage and "ENABLED SYSTEM".

LRESULT onHotKey (WPARAM wparam, LPARAM lparam)
{
if (wcscmp (lastMessage, L"ENABLED SYSTEM") == 0)
{
ShellExecuteW(hwndMain, L"open", L"C:\\enabled_graph.exe", NULL, NULL, SW_SHOW);
} else {
MessageBox(NULL, L"NOT EXECUTING", L"NO", 0);
}
return 0;
}

3. Once in a while, when I compile, it will have this error:

Linking...
LINK : fatal error LNK1104: cannot open file "..\binfiles\x86_unicode_debug/event.dll"
Error executing link.exe.

Even I didn't change anything, it seems to be happen whenever it likes. And I have to copy and paste the whole folder and put in another name and use the new one. But after compiling a few times, this happen again! :-( Why it does this to me ... :-(

More and more problems.... Nearly fainted :-S

Any idea, please?

Thanks,

samcct
March 27th, 2006, 06:58 PM
Hi Golarshahar,

I found out one thing!!!!! But need your expertise... THis is my code:

LRESULT onHotKey (WPARAM wparam, LPARAM lparam)
{
_bstr_t strTmp (lastMessage);
::OutputDebugString(strTmp);
/*if (wcscmp (lastMessage, L"WORKING SYSTEM") == 0)
{
MessageBox(NULL, L" EXECUTING", L"OK", 0);
} else {
MessageBox(NULL, L"NOT EXECUTING", L"NO", 0);
}*/
return 0;
}

I suppose here is the main problem, so I print out the lastMessage to see what it is. Oddly enough, this is the results:

When the name is WORKING SYSTEM - Output: WORKINGw????0
WHen the name is http://www.enabledweb.org/samantha/system.html - Output: http://www.enabledweb.????0

That's the reason I can't compare it with my "WORKING SYSTEM"!!!! But is this happen? Is it something about me allocating the string?

Thanks loads.

golanshahar
March 28th, 2006, 04:13 AM
So you are saying that lastMessage doesnt get the correct value?
in that case the following:

if (wcscmp (lastMessage, L"WORKING SYSTEM") == 0)


always false right? is this the case?

Cheers

samcct
March 28th, 2006, 07:07 AM
Hi Golanshahar, yeah... I just realized that... it just got the first parts (or the first few words of the name. For exmaple, if the name suppose to be WORKING SYSTEM, it outputs as WORKING????0.... the back part always symbols or 0.

So it always go to false, yeah.

And also, if no window opened after execution, then the program hang there if I press the keys.

THanks,

Samantha

(sorry, was away for a seminar earlier on)..

samcct
March 28th, 2006, 03:39 PM
Hi Golanshahar, I was still looking through the code. I was wondering if the mistakes happened while I set and retrieve the variable (BSTR storage and BSTR lastMessage) which consequently create this error where it only read the first part of the data...

The codes involved are only those you suggested to me and I hope I did them correctly.... Any idea where I should look into again?

Many thanks,
Sam

golanshahar
March 28th, 2006, 03:43 PM
Are you sure that before posting the BSTR from the dll the data this BSTR contains is ok?
Can popup a message box to see if before you send the BSTR the value is ok before sending?.

Cheers

samcct
March 28th, 2006, 03:56 PM
Are you sure that before posting the BSTR from the dll the data this BSTR contains is ok?
Can popup a message box to see if before you send the BSTR the value is ok before sending?.

Cheers

Hi golanshahar, Yeah.... I already did that before and i tried it again a minute ago just to make sure... They are the right value even in that FindWindow loop before and after sysAllocString....

Thx...

golanshahar
March 28th, 2006, 04:22 PM
Post the project again I will look into it when I’ll have time, just mark the places where you added the code.

And tell me what is the scenario I need to do in order to see the problem

Cheers

samcct
March 28th, 2006, 04:57 PM
Post the project again I will look into it when I’ll have time, just mark the places where you added the code.

And tell me what is the scenario I need to do in order to see the problem

Cheers

Hi golanshahar,

Basically I only added codes in this two files: accevent.cpp and objects.cpp ( I commented as MY ADDED CODE).

1. To see if BSTR value has correct value before sending, see "objects.cpp", the line:
str << TEXT (" the name==== ") << storage << TEXT("!!!!!");
In the ENABLED EXPLORER box, you can see this is the same as the name.

2. To see the value after sent, pls refer to accevent.cpp, the onHotKey function at the bottom of the page.

_bstr_t strTmp (lastMessage);
::OutputDebugString(strTmp);

This can be see in the debugging box when you press the SHIFT+E keys. You can see the value is only first part of the name with strange symbols after that.

3. If you use uncomment the lines in the onHotKey where the comparison happen - if (wcscmp (lastMessage, L"ENABLED SYSTEM") == 0) - when you press the SHIFT+E keys, you can see it always FALSE.

And I have added urlmon.lib to my link setting (for URLDownloadTOFile).

I think basically this is it.... I will keep looking into it too... Thanks for your helps and your time.... Appreciate it, indeed..

Thanks a lot... Samantha

golanshahar
March 29th, 2006, 07:41 AM
Look at the attached project.

Cheers

samcct
March 29th, 2006, 09:42 AM
Look at the attached project.

Cheers

Thanks a million, golanshahar!

But could I know why it is not working if we use the previous method - sysAllocString?

I see how you did that with memset, strncpy. But one question: I know memset is to fill the first n bytes of the memory area pointed to be s with the constant byte c - for void *memset(void *s, int c, size_t n);
Why for the 2nd parameter, you set "0" on it? Why can't we straight away use strncpy instead of filling it in the memory?

Actually I need to retrieve 2 values from the objects.cpp (the name and it's description if the name match to my button). I was trying to use the same method for the 2nd value. Then I found out it might not be able to send more than one data to the accevent.cpp via WM_COPYDATA. Is it right or it is actually possible?

Many many thanks... Sam

golanshahar
March 29th, 2006, 03:36 PM
But could I know why it is not working if we use the previous method - sysAllocString?

I found one major bug:

COPYDATASTRUCT cd={0};
cd.lpData = storage;
cd.cbData = ::SysStringLen(storage);
::SysFreeString(storage);
::SendMessage (hApp,WM_COPYDATA,0,(LPARAM)&cd);


You are calling ::SysFreeString() before the WM_COPYDATA you are simply freeing the string before you send it. Anyway that was the major one :D


I see how you did that with memset, strncpy. But one question: I know memset is to fill the first n bytes of the memory area pointed to be s with the constant byte c - for void *memset(void *s, int c, size_t n);
Why for the 2nd parameter, you set "0" on it? Why can't we straight away use strncpy instead of filling it in the memory?

memset with 0 setting the whole buffer to 0. The reason I did is since strncpy() doesn’t add '\0' in the end of the copied string I simply make sure that the buffer will be initialized with 0 so there will be always '\0' in the end of the string.:)


Actually I need to retrieve 2 values from the objects.cpp (the name and it's description if the name match to my button). I was trying to use the same method for the 2nd value. Then I found out it might not be able to send more than one data to the accevent.cpp via WM_COPYDATA. Is it right or it is actually possible?

Yes, one thing you can do is create a struct that contains two char[] arrays and send this struct, just dont forget to set the size of the struct in the cbData variable. ;)

Cheers

samcct
March 29th, 2006, 04:08 PM
Yes, one thing you can do is create a struct that contains two char[] arrays and send this struct, just dont forget to set the size of the struct in the cbData variable. ;)

Cheers

I don't really get you about the this. This is what I am trying to do, I am sure there are a lot of mistakes here. Because I only want the name and its description, so...

<<objects.cpp>>

struct NameValue
{
char[] nameValue;
char[] descValue;
}

void GetObjProp_Name( IAccessible * pAcc, VARIANT * pvarChild, StrWrPos & str )
{
count = 1;
GetObjProp_GenericStr( pAcc, pvarChild, str, & IAccessible::get_accName, DISPID_ACC_NAME );
}

void GetObjProp_Description( IAccessible * pAcc, VARIANT * pvarChild, StrWrPos & str )
{
count = 2;
GetObjProp_GenericStr( pAcc, pvarChild, str, & IAccessible::get_accDescription, DISPID_ACC_DESCRIPTION );
}

void GetObjProp_GenericStr( IAccessible * pAcc, VARIANT * pvarChild, StrWrPos & str, PMTH_IAccGetStr pmthGetStrProp, DISPID DispID )
{
//..........
HWND hApp = ::FindWindow(0,L"ENABLED EXPLORER");
if ( hApp )
{
if (count == 1) {
storageName = bstrName;
COPYDATASTRUCT cd={0};
_bstr_t b(storageName);
//char s[MAX_PATH]={0};
strcpy(nameValue,b);
cd.cbData = sizeof(nameValue);
cd.lpData = nameValue;
::SendMessage (hApp,WM_COPYDATA,0,(LPARAM)&cd);
str << TEXT (" the name= ") << storageName << TEXT("!!");
} else if (count == 2) {
storageDesc = bstrName;
COPYDATASTRUCT cds={0};
_bstr_t de(storageDesc);
//char ds[MAX_PATH]={0};
strcpy(descValue,de);
cds.cbData = sizeof(descValue);
cds.lpData = descValue;
::SendMessage (hApp,WM_COPYDATA,0,(LPARAM)&cds);
str << TEXT (" the desc= ") << storageDesc << TEXT("!!");
}
}
}

<<accevent.cpp>>
char lastName[MAX_PATH];
char lastDesc[MAX_PATH];

case WM_COPYDATA:
{
COPYDATASTRUCT *cN = ( COPYDATASTRUCT*)lParam;
memset(lastName,0,sizeof(lastName));
strncpy(lastName,(char*)cN->lpData,cN->cbData);

COPYDATASTRUCT *cD = ( COPYDATASTRUCT*)lParam;
memset(lastDesc,0,sizeof(lastDesc));
strncpy(lastDesc,(char*)cD->lpData,cD->cbData);
}
break;

LRESULT onHotKey (WPARAM wparam, LPARAM lparam)
{
if (strcmp (lastName, "ENABLED SYSTEM") == 0)
{
urlDownload = URLDownloadToFile(NULL, lastDesc, L"C:\\myFile.xls", NULL, NULL);
} else {
MessageBox(NULL, L"NOT EXECUTING", L"NO", 0);
}
return 0;
}

:S As expected, it is not working... still learning about struct...

Thanks.... Sam

golanshahar
March 29th, 2006, 04:23 PM
Look at the attached project.

Cheers

samcct
March 29th, 2006, 06:54 PM
Thanks golanshahar... But I'm afraid this is not the the result my code needs...

The way the code run in that part is: it uses the same function (GetObjProp_GenericStr()) to get the name and the value. It goes on the for-loop in the ObjectProc() function. So it will first get the name and then go for another loop in GetObjProp_GenericStr() to get the description for this name. So actually both of them are sharing one variable, which is the bstrName. So in your code, you said I can put other string that I want in strcpy(nv.descValue,L"the string");
but I can't do that as they are sharing the same string => bstrName. If you can see what I mean here?

I did it like this, hoping it will only SendMessage after it finished collecting both name and description (means after it goes on the second loop). So I did it in this way:

HWND hApp = ::FindWindow(0,L"ENABLED EXPLORER");
if ( hApp )
{
COPYDATASTRUCT cd={0};
storage = bstrName;
_bstr_t b(storage);;
NameValue nv={0};
strcpy(nv.nameValue,b);
if (count == 2) {
storageDesc = bstrName;
_bstr_t c(storageDesc);
strcpy(nv.descValue,c); // put here the string you want.
cd.cbData = sizeof(nv);
cd.lpData = &nv;
::SendMessage (hApp,WM_COPYDATA,0,(LPARAM)&cd);
}
str << TEXT (" the name= ") << storage << TEXT("!!!!!");
}

***********************************
void GetObjProp_Description( IAccessible * pAcc, VARIANT * pvarChild, StrWrPos & str )
{
count = 2;
GetObjProp_GenericStr( pAcc, pvarChild, str, & IAccessible::get_accDescription, DISPID_ACC_DESCRIPTION );
}
***********************************

In the accevent.cpp, I didn't change anything. But when I OutputDebugString in the onHotKey function for both lastMessage1 and lastMessage2, both show the same, which is the description (not the name for the lastMessage1)....

How could I fix this problem? Thanks loads.

:( Sam (need to get it done by end of this week... Get really nervous :( )

golanshahar
March 30th, 2006, 05:04 AM
Not sure what you need exactly but if you want to send different data with WM_COPYDATA you can set the dwData member of the COPYDATASTRUCT with some number lets say 0,1,2 etc..

And on the receiving side when you can the WM_COPYDATA you can check that value:

if ( cd->dwData == 0 )
{
// copy to lastMessage
}
if ( cd->dwData == 1 )
{
// copy to lastMessage2
}


Hope it helps.

Cheers

samcct
March 30th, 2006, 05:47 AM
Thanks golanshahar. Ok... I will have a go with this dwData. Btw, at the sending side, do I have to repeat this whole bunch of codes each time I am sending the value (lets say I want to send three value, then that means I have to have these codes for three times)?

_bstr_t b(storageDesc);
NameValue nv={0};
strcpy(nv.descValue,b); // put here the other string you want.
cd.dwData = 0;
cd.cbData = sizeof(nv);
cd.lpData = &nv;
::SendMessage (hApp,WM_COPYDATA,0,(LPARAM)&cd);

I have another question, if I could get the lastMessage2 from the above approach, then I want to use that value as my url for URLDownloadToFile.

urlDownload = URLDownloadToFile(NULL, lastMessage2, L"C:\\myFile.txt", NULL, NULL);

But then I will get an error, something like this:-

Can't convert parameter 2 from "char[260]" to "const unsigned short*"

How could I change the lastMessage type so that I can use as the 2nd parameter in this function?

Thanks a lot..... Sam

PS: Is golanshahar a nickname for you? Just for acknowledgement.

damentor
March 30th, 2006, 12:12 PM
There is good tutorial on this link

http://www.codeguru.com/vb/gen/vb_system/keyboard/article.php/c4829/

golanshahar
March 30th, 2006, 01:50 PM
Thanks golanshahar. Ok... I will have a go with this dwData. Btw, at the sending side, do I have to repeat this whole bunch of codes each time I am sending the value (lets say I want to send three value, then that means I have to have these codes for three times)?

_bstr_t b(storageDesc);
NameValue nv={0};
strcpy(nv.descValue,b); // put here the other string you want.
cd.dwData = 0;
cd.cbData = sizeof(nv);
cd.lpData = &nv;
::SendMessage (hApp,WM_COPYDATA,0,(LPARAM)&cd);

If you can set all variables to one struct at one time then you can send it in one goal, but if you need to send data from different places/times in the dll then for each data send there should be a call to ::SendMessage(), and no you dont have to copy paste the code to all spots you need to call ::SendMessage() that is why there are functions. ;)


I have another question, if I could get the lastMessage2 from the above approach, then I want to use that value as my url for URLDownloadToFile.

urlDownload = URLDownloadToFile(NULL, lastMessage2, L"C:\\myFile.txt", NULL, NULL);

But then I will get an error, something like this:-

Can't convert parameter 2 from "char[260]" to "const unsigned short*"

How could I change the lastMessage type so that I can use as the 2nd parameter in this function?

you can convert char* to wchar_t using ::MultiByteToWideChar() (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_17si.asp).
here is a sample:

char lastMessage2[MAX_PATH]={"www.myurl.com"};

wchar_t wText[MAX_PATH]={0};
::MultiByteToWideChar( CP_ACP, NULL,lastMessage2, -1, wText,sizeof(wText) );
// use wText to call URLDownloadToFile()




PS: Is golanshahar a nickname for you? Just for acknowledgement.

It’s my real name Golan Shahar ;)

Cheers

samcct
March 30th, 2006, 03:27 PM
Hi Golan, THANK YOU!!!!!!!

It works perfectly now!!!!! Thanks a million for your helps and patience. Really appreciate it...

Just a few questions again for my own understanding (if you don't mind).

1. Why we always need to add two semi-colons in front of some of the codes (for example, ::MultiByteToWideChar, ::SendMessage, etc.)? I did some simpler codes before and also from those examples, sometimes we don't need the two ::.

2. What is these two types: _bstr_t and _wchar_t? I tried to find them in google, but can't find an explanation about them (why they start with _)?

3. How I can know what else type or structure available, for example, COPYDATASTRUCT, VARIANT, HINSTANCE, UINT, LPSTR, BSTR,....? There are so many... and also, when I start from the most basic, I knew about char, int, long, etc... but now I realized there are more like BSTR, const unsigned short, etc... a lot!!!!

Again, thanks to you and sorry for keep asking questions. Thanks for your time.

Samantha :)

golanshahar
March 30th, 2006, 03:59 PM
Hi Golan, THANK YOU!!!!!!!

It works perfectly now!!!!! Thanks a million for your helps and patience. Really appreciate it...

You are welcome :wave:


1. Why we always need to add two semi-colons in front of some of the codes (for example, ::MultiByteToWideChar, ::SendMessage, etc.)? I did some simpler codes before and also from those examples, sometimes we don't need the two ::.

Look at this thread: Adv/Disadv of Scope Resolution Operator (http://www.codeguru.com/forum/showthread.php?t=369114&p=1294192)


2. What is these two types: _bstr_t and _wchar_t? I tried to find them in google, but can't find an explanation about them (why they start with _)?

You can find info about them in the msdn:

_bstr_t (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_pluslang__bstr_t.asp)
wchar_t (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_langref_data_type_ranges.asp)



3. How I can know what else type or structure available, for example, COPYDATASTRUCT, VARIANT, HINSTANCE, UINT, LPSTR, BSTR,....? There are so many... and also, when I start from the most basic, I knew about char, int, long, etc... but now I realized there are more like BSTR, const unsigned short, etc... a lot!!!!

You can look in the MSDN, however the knowledge of those types is available by practice the more you will write programs the more you will be experienced and exposed to more API/Data types.
You don’t have to know them all in order to program, what you should know is to work with MSDN read the help and then it will be easy.


Again, thanks to you and sorry for keep asking questions. Thanks for your time.

Samantha :)

Its ok, that why we have the forum for asking questions and of course getting the answers :D

Cheers

samcct
March 31st, 2006, 12:17 PM
Hi Golan,

One quick question, I need to add the mouse click in the project now, so that when the user left click on the button, then it will do the same thing as the user presses on the SHIFT+E keys.

My idea is to know the moment the user left click then I will compare with the lastMessage with the button name.

Can you suggest what is the best way for me to know when the user left click? I was looking at WM_LBUTTONDOWN, but there are two things:

1. From what I understand from msdn, it is only work when the cursor is over that window, which is not enough for my case, as I want anywhere they click.

2. Is there anywhere I need to register (like the WM_HOTKEY, I need to registerHotKey when INITDIALOG). Or I don't have to register, and once the user left clicks, then it will send the message as WM_LBUTTONDOWN?

Thanks.

golanshahar
March 31st, 2006, 12:37 PM
Take a look at ::SetCapture() (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/mouseinput/mouseinputreference/mouseinputfunctions/setcapture.asp).

Cheers

samcct
March 31st, 2006, 04:24 PM
Take a look at ::SetCapture() (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/mouseinput/mouseinputreference/mouseinputfunctions/setcapture.asp).

Cheers

Hi GolanShahar,

Thanks for your suggestion. I used SetCapture() but I am not sure if it's because I put it in the wrong place or I used it wrongly.

I saw some examples with SetCapture(hwnd) in the case WM_LBUTTONDOWN. But for mine, whenever I click on anywhere, it doesn't go into that WM_LBUTTONDOWN function at all. Anything I put in the case WM_LBUTTONDOWN, nothing happen. It should go into this case WM_LBUTTONDOWN once I click on left button, am i right? I saw almost of the examples and tutorials which work in this way. But why mine is not working in this way?

Then I tried on this:

LRESULT CALLBACK
MainWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
SetCapture(hwnd);
switch( uMsg )
{
case WM_LBUTTONDOWN:
{
onLeftButtonDown (wparam, lparam);
}
}
}

Is this not the right way? It seems like it will only do something when i click on my project window for the first time. Could you kindly advise?

Thanks... Sam

samcct
April 1st, 2006, 05:07 AM
As far as I understand, I don't have to register the mouse event (not like keyboard, we need to RegisterHotKey). And whenever we click the mouse button, it will automaticallly send the message (eg. WM_LBUTTONDOWN). Just want to know if this is right because for mine, it isn't work like this.

Many Thanks,

golanshahar
April 1st, 2006, 11:11 AM
As far as I understand, I don't have to register the mouse event (not like keyboard, we need to RegisterHotKey). And whenever we click the mouse button, it will automaticallly send the message (eg. WM_LBUTTONDOWN). Just want to know if this is right because for mine, it isn't work like this.

Many Thanks,

This is how ::SetCapture() works, read the msdn:

The SetCapture function sets the mouse capture to the specified window belonging to the current thread. SetCapture captures mouse input either when the mouse is over the capturing window, or when the mouse button was pressed while the mouse was over the capturing window and the button is still down. Only one window at a time can capture the mouse.



What exactly you are doing? If this isn’t enough for you, you can use mouse hooking.

Cheers

samcct
April 1st, 2006, 11:29 AM
sorry for keep asking. I only ask if I can't find understand why it is not working. I already read the msdn about capture. I uses WM_LBUTTONDOWN first of all.

And from what I understand from the examples and msdn, I understand that I don't have to register anything to use WM_LBUTTONDOWN. As long as I click on mouse button, it should fire this message. But I just can't understand why it doesn't fire this message to mine. I just asking if I did the right way, or i missed out something important. It is exactly what I found from the Internet. It should be quite straighforward.

Apart from launching the program with shift and E keys, I want to do the same thing for right click on the button.

Thanks,

samcct
April 1st, 2006, 12:11 PM
Sorry. What I need to make it work is, I want to know the moment the user click on the left button, and then I will compare the focus name with the specific name. ANd if it is the same name, then it will do something. Just like when the user presses on the keys, I compare the name and do something.

I just added in the case WM_LBUTTONDOWN and assume I can add what I want to do in there. But wierd thing it seems that nothing happen even I use OutputDebugString or MessageBox in this case to debug. Nothing happen when I click on anywhere.

Need your advice. Thanks.

golanshahar
April 1st, 2006, 01:38 PM
Sorry. What I need to make it work is, I want to know the moment the user click on the left button, and then I will compare the focus name with the specific name. ANd if it is the same name, then it will do something. Just like when the user presses on the keys, I compare the name and do something.

I just added in the case WM_LBUTTONDOWN and assume I can add what I want to do in there. But wierd thing it seems that nothing happen even I use OutputDebugString or MessageBox in this case to debug. Nothing happen when I click on anywhere.

Need your advice. Thanks.

I told you to look in the msdn, cause with these requirements ::SetCapture() wont help you, it seems like your window may not be foreground.
Anyway the only alternative I can think of is to use mouse hooks.

You can look at this article (http://www.codeproject.com/dll/trackuseridle.asp) it does other things but also shows how to use mouse hook.

Cheers

samcct
April 2nd, 2006, 07:38 AM
I told you to look in the msdn, cause with these requirements ::SetCapture() wont help you, it seems like your window may not be foreground.
Cheers

I don't really get this line or what explained in msdn, golanshahar. I thought to be a foreground window, it is the window on top of other windows. And it should work if I click on one of the window, no?

<<msdn>>
The WM_LBUTTONDOWN message is posted when the user presses the left mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.

OK, if I don't think of anything yet, I just want to test on WM_LBUTTONDOWN:
One thing I really can't understand is the WM_LBUTTONDOWN. OK, from the msdn, it says once the left button is clicked in the client window, then this message will be fired. So I suppose when i click on my created window, it will fire this message. I just want to find out why is this not working when i tried it in my program (although I know this is not I want for my program, but just to learn more about it)? I tried on MOUSEMOVE, etc, they don't work too. WHy is that? From examples, they said this message will definitely be fired once the left button is clicked or move....

One last thing, by your expertise, do you think I can use WM_NOTIFY and NM_CLICK to detect only left clicking on IE Window?

Sorry, I don't like to keep asking as well, but just can't figure out what happen. Hope you understand. Thanks.

golanshahar
April 2nd, 2006, 08:40 AM
I don't really get this line or what explained in msdn, golanshahar. I thought to be a foreground window, it is the window on top of other windows. And it should work if I click on one of the window, no?

<<msdn>>
The WM_LBUTTONDOWN message is posted when the user presses the left mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Top window is not necessarily a foreground window if you will open for instance the task manager and click on other window let say notepad you will be able to write on notepad (since it has the focus after you clicked on it) while the task manger is still the top window.


OK, if I don't think of anything yet, I just want to test on WM_LBUTTONDOWN:
One thing I really can't understand is the WM_LBUTTONDOWN. OK, from the msdn, it says once the left button is clicked in the client window, then this message will be fired. So I suppose when i click on my created window, it will fire this message. I just want to find out why is this not working when i tried it in my program (although I know this is not I want for my program, but just to learn more about it)? I tried on MOUSEMOVE, etc, they don't work too. WHy is that? From examples, they said this message will definitely be fired once the left button is clicked or move....

Well it should work. don’t know why you have difficulties with it :confused: post the code.


One last thing, by your expertise, do you think I can use WM_NOTIFY and NM_CLICK to detect only left clicking on IE Window?

:ehh: you question is not clear to me, IE window is a different window in a different process, if you want to catch clicks there you should use mouse hook like already suggested.

Cheers

samcct
April 2nd, 2006, 08:52 AM
Top window is not necessarily a foreground window if you will open for instance the task manager and click on other window let say notepad you will be able to write on notepad (since it has the focus after you clicked on it) while the task manger is still the top window.

Well it should work. don’t know why you have difficulties with it :confused: post the code.

Cheers

I only add the WM_LBUTTONDOWN in the switch for MainWinProc callback function.

I just realize it is not appropriate to use WM_NOTIFY. THanks.

I just want to do the same thing as the key pressed action. When left click, check the name of object is being focused and if the same as the one i want, then launch the local application.

Thanks,

PS: I posted other threads about WM_LBUTTONDOWN in general. Hope you won't mind, as I really feel bad keep asking you but you are really a good help to me, as I really appreciate your patience. Need this to work by tomorrow :(

samcct
April 2nd, 2006, 10:05 AM
Hi golanshahar,

Actually I tried not to use any hook function again for the mouse event if there are other ways I can use. That's why I hope something simpler like WM_LBUTTONDOWN can work in code.

I read through the article you suggested. To be honest, as my program involves a few things at once, I don't know where to start or where I should do those, whether in the exe or dll and which files...

golanshahar
April 2nd, 2006, 11:59 AM
Hi golanshahar,

Actually I tried not to use any hook function again for the mouse event if there are other ways I can use. That's why I hope something simpler like WM_LBUTTONDOWN can work in code.

I read through the article you suggested. To be honest, as my program involves a few things at once, I don't know where to start or where I should do those, whether in the exe or dll and which files...

If you want to trap mouse events from outside your application you should be using hooks, trapping the WM_LBUTTONDOWN wont help you here cause you will get that message only when mouse in your window borders and this is not what want (if i understood correctly what you trying to achieve). :o

Cheers