SendMessage() & Co funktionieren nicht



  • Hallo,
    ich hab mit Google und auch hier im Forum schon einiges gelesen zu der SendMessage() bzw. PostMessage() Funktion.

    Ich weiß leider nicht was ich falsch mache.

    Ich möchte per Fernsteuerung Tastendrücke und Mausklicks an ein anderes Programm senden, so als ob ein Benutzer tatsächlich vor dem PC sitzt und mit der Maus klickt und mit der Tastatur was schreibt.

    Für den Anfang soll es genügen dass Notepad meine simulierten Tastendrücke empfängt.

    Im Prinzip sieht das in meinem Quellcode so aus:

    while(1)
    {
      Sleep(2000);
      SendMessage(receiverHWND,WM_KEYDOWN,'A',0);
      Sleep(50);
      SendMessage(receiverHWND,WM_KEYUP,'A',0);
    }
    

    receiverHWND ist das HWND von Notepad, das ist sichergestellt.

    Mach ich da irgendwas gravierend falsch? Jedenfalls kommt im Notepad nichts an. Kann es sein dass ich noch eine ganze Reihe anderer Messages losschicken muss bevor ich WM_KEYDOWN und WM_KEYUP sende, damit Notepad die Messages überhaupt verarbeitet?

    WM_LBUTTONDOWN & Co funktionieren auch nicht.

    Was jedoch funktioniert ist

    mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
    

    usw.

    Aber wie mache ich das mit SendMessage korrekt?

    Edit: Ich benutze Windows XP.

    MfG





  • Vielen Dank für deine Antwort erst mal!

    Sowas hab ich auch schon gelesen. Aber wie komme ich an die Thread-Id des Empfänger-Programms?

    MfG



  • Wofür brauchst Du den Thread-Id des Empfänger-Programms?

    Ich sehe in Deinem Code, daß Du bereits den HWND vom Fenster des Empfänger-Programm ermittelt haben müßtest (receiverHWND).

    Dann verwende SetFocus() mit diesem HWND, und dieses Fenster erhält dann automatisch die simulierten Nachrichten von SendInput().

    Natürlich darf dieses Fenster nicht minimiert sein o.ä., denn minimierte Fenster können per Definition kein Fokus erhalten.

    Martin



  • Wenn ich deinem Link folge dann steht da dass man den Thread des Empfängers irgendwie mit AttachThreadInput(...) mit dem eigenen Thread verküpfen muss. Also jedenfalls hab ich jetzt die ThreadId doch herbekommen mit der Funktion GetWindowThreadProcessId().

    SetFocus() funktioniert leider nicht 😞
    Dafür funktioniert WM_SETFOCUS mit SendMessage().

    Nun kann ich ja eigentlich den Rest mit keybd_event(...) und mouse_event(...) machen...

    ...es scheint soweit mal zu funktionieren.

    Vielen Dank für den Link in deinem ersten Post. Vielleicht hast du bemerkt dass ich da darauf mal geantwortet hatte und das dann wieder gelöscht hatte. In meinem Über-Eifer hab ich ein falsches Handle übergeben und dann kam es wieder zum Absturz und in Panik hab ich hier wieder um Hilfe gerufen. Wie peinlich von mir...

    Also insgesamt sieht das jetzt im Prinzip so aus:

    DWORD notePadProcessId;
    DWORD simulatorProcessId;
    DWORD notePadThreadId;
    DWORD simulatorThreadId;
    while(1)
    {
      Sleep(2000);
    
      notePadThreadId = GetWindowThreadProcessId(notePadHWND,&notePadProcessId);
      simulatorThreadId = GetWindowThreadProcessId(simulatorHWND,&simulatorProcessId);	  
      AttachThreadInput(notePadThreadId,simulatorThreadId,true);
      SendMessage(notePadHWND,WM_SETFOCUS,0,0);
    
      keybd_event(VK_LSHIFT,0,0,0);
      keybd_event('A',0,0,0);
      keybd_event('A',0, KEYEVENTF_KEYUP,0);
      keybd_event(VK_LSHIFT,0, KEYEVENTF_KEYUP,0);	
    
      AttachThreadInput(notePadThreadId,simulatorThreadId,false);
    }
    

    Ich muss ja hier zum Glück keine Texte verschicken, ich werde mir SendInput aber trotzdem nochmal anschauen.

    Vielen Dank nochmal, Mmacher!!!


  • Mod

    WM_SETFOCUS darf man nicht senden. Man muss SetFocus als Funktion verwenden..
    http://blog.m-ri.de/index.php/2007/12/24/die-unsitte-windows-interne-nachrichten-zu-versenden/

    Auch hier musst Du zuerst mit AtachThreadInput an den Thread kommen und dann kann man auch SetFocus korrekt ausführen. Siehe auch MSDN Doku!



  • Sorry für die Verspätung, bin erst seit heut wieder bei der Arbeit.

    SetFocus(...) funktioniert definitiv nicht. Das andere Programm bekommt den Focus nicht und demzufolge auch keine Tastatur- und Mausinputs.

    Irgendeine Idee, was ich falsch machen könnte??


  • Mod

    SetFocus funktioniert definitv, wenn man es richtig macht und AttachThreadInput verwendet.

    Siehe MSDN zu SetFocus:
    http://msdn.microsoft.com/en-us/library/ms646312(VS.85).aspx

    By using the AttachThreadInput function, a thread can attach its input processing to another thread. This allows a thread to call SetFocus to set the keyboard focus to a window attached to another thread's message queue.



  • Ich benutze ja die AttachThreadInput(...)-Funktion. Siehe Quellcode in meinem Beitrag oben.

    Ich ersetze hier

    SendMessage(notePadHWND,WM_SETFOCUS,0,0);
    

    durch

    SetFocus(notePadHWND);
    

    Notepad bekommt den Fokus dann aber nicht.

    Was mach ich falsch?


  • Mod

    Du benutzt AttachThreadInput nicht korrekt... Was gibt denn die Funktion zurück?



  • AttachThreadInput(notePadThreadId,simulatorThreadId,true);
    

    gibt true zurück.

    und

    AttachThreadInput(notePadThreadId,getWindowServerThreadId,false);
    

    gibt ebenfalls true zurück.


  • Mod

    Dann zeig mal den kompletten Code Abschnitt.



  • #include "stdafx.h"
    #include "Test.h"
    
    #define MAX_LOADSTRING 100
    
    HINSTANCE hInst;					
    TCHAR szTitle[MAX_LOADSTRING];				
    TCHAR szWindowClass[MAX_LOADSTRING];	
    
    ATOM				MyRegisterClass(HINSTANCE hInstance);
    BOOL				InitInstance(HINSTANCE, int);
    LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
    INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++
    BOOL CALLBACK SucheWindow(HWND enumHWND,LPARAM lParam);
    void sendeMausKlicks(LPVOID p);
    
    HWND notepadHWND = NULL;
    HWND simulatorHWND = NULL;
    
    HDC notepadHDC = NULL;
    LPVOID p;
    //-----------------------------------------------------
    int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
    {
    	UNREFERENCED_PARAMETER(hPrevInstance);
    	UNREFERENCED_PARAMETER(lpCmdLine);
    	MSG msg;
    	HACCEL hAccelTable;
    	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    	LoadString(hInstance, IDC_TEST, szWindowClass, MAX_LOADSTRING);
    	MyRegisterClass(hInstance);
    	if (!InitInstance (hInstance, nCmdShow))
    	{
    		return FALSE;
    	}
    	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TEST));
    
    	//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    	EnumWindows(SucheWindow,NULL);
    	DWORD mausKlickThreadId;
    	CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)sendeMausKlicks,p,0,&mausKlickThreadId);
    	//--------------------------------------------------------------------------------------------------------------------------
    
    	while (GetMessage(&msg, NULL, 0, 0))
    	{
    		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    		{
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    	}
    
    	return (int) msg.wParam;
    }
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
    	WNDCLASSEX wcex;
    
    	wcex.cbSize = sizeof(WNDCLASSEX);
    
    	wcex.style			= CS_HREDRAW | CS_VREDRAW;
    	wcex.lpfnWndProc	= WndProc;
    	wcex.cbClsExtra		= 0;
    	wcex.cbWndExtra		= 0;
    	wcex.hInstance		= hInstance;
    	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TEST));
    	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
    	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
    	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_TEST);
    	wcex.lpszClassName	= szWindowClass;
    	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    
    	return RegisterClassEx(&wcex);
    }
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       HWND hWnd;
    
       hInst = hInstance;
    
       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
    
       if (!hWnd)
       {
          return FALSE;
       }
       //+++++++++++++++++++
       simulatorHWND = hWnd;
       //-------------------
    
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
    
       return TRUE;
    }
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	int wmId, wmEvent;
    	PAINTSTRUCT ps;
    	HDC hdc;
    
    	switch (message)
    	{
    	case WM_COMMAND:
    		wmId    = LOWORD(wParam);
    		wmEvent = HIWORD(wParam);
    		switch (wmId)
    		{
    		case IDM_\1:
    			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
    			break;
    		case IDM_EXIT:
    			DestroyWindow(hWnd);
    			break;
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    		}
    		break;
    	case WM_PAINT:
    		hdc = BeginPaint(hWnd, &ps);
    		EndPaint(hWnd, &ps);
    		break;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	default:
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	UNREFERENCED_PARAMETER(lParam);
    	switch (message)
    	{
    	case WM_INITDIALOG:
    		return (INT_PTR)TRUE;
    
    	case WM_COMMAND:
    		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
    		{
    			EndDialog(hDlg, LOWORD(wParam));
    			return (INT_PTR)TRUE;
    		}
    		break;
    	}
    	return (INT_PTR)FALSE;
    }
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    BOOL CALLBACK SucheWindow(HWND enumHWND,LPARAM lParam)
    {
    	LPTSTR str1 = new WCHAR[100]; 
    	LPTSTR str2 = L"Unbenannt - Editor";
    	int x=0;
    	bool b = true;
    	GetWindowText(enumHWND,str1,100);
    
    	while(str2[x]!=0 && b)
    	{
    		b = str1[x]==str2[x]; 
    		x++;
    	}
    	if(b)
    	{
    		notepadHWND = enumHWND;
    		p = (LPVOID)enumHWND;
    		notepadHDC = GetDC(enumHWND);
    		return false;
    	}
    	return true;
    }
    void sendeMausKlicks(LPVOID p)
    {
    	HANDLE h = (HANDLE)p;
    	DWORD notePadProcessId;
    	DWORD simulatorProcessId;
    	DWORD notePadThreadId;
    	DWORD simulatorThreadId;
    	while(1)
    	{
    		Sleep(2000);
    		notePadThreadId = GetWindowThreadProcessId(notepadHWND,&notePadProcessId);
    		simulatorThreadId = GetWindowThreadProcessId(simulatorHWND,&simulatorProcessId);
    		AttachThreadInput(notePadThreadId,simulatorThreadId,true);
    
    		//SendMessage(notepadHWND,WM_SETFOCUS,0,0);	
    		SetFocus(notepadHWND);
    
    		keybd_event(VK_LSHIFT,0,0,0);
    		keybd_event('A',0,0,0);
    		keybd_event('A',0, KEYEVENTF_KEYUP,0);
    		keybd_event(VK_LSHIFT,0, KEYEVENTF_KEYUP,0);
    
    		AttachThreadInput(notePadThreadId,simulatorThreadId,false);
    	}
    }
    //--------------------------------------------------------------------------------------
    

    Das meiste vom Code wurde von Visual C++ 2008 Express Edition automatisch generiert. Meine änderungen beginnen mit dem Kommentar
    //++++++++++++++++
    und enden mit
    //----------------

    Erst NotePad leer starten (so dass es den Titel "Unbenannt - Editor" hat) und dann das Programm starten.

    MfG



  • Hey Martin,
    hast du schon was herausgefunden wieso das mit SetFocus(HWND) nicht funktioniert? Im Moment funktioniert es ja mit SendMessage(...), aber wenn das nicht immer funktioniert oder irgendwie auch sonst unschön ist, würde ich doch gerne lieber SetFocus(HWND) benutzen...

    Aber trotzdem danke für deine Hilfe!!!

    MfG


  • Mod

    Es müsste IMHO so lauten:

    AttachThreadInput(simulatorThreadId,notePadThreadId,true);
    


  • Nein, funktioniert leider auch nicht. 😞



  • Hallo SchlechterInformatiker,

    eines vorneweg: Bitte benutze hier im Forum als Code-Tag den Button "C/C++" (und nicht den Button "Code"), dann ist Dein Source-Code deutlich besser lesbarer (Syntax-Coloring).

    Nun, soweit ich mich erinnern kann, sind Deine übergebenen Parameter für AttachThreadInput() falsch (Thread-IDs vertauscht?) 🙄
    Das folgende Schema sollte richtig sein:

    if ( AttachThreadInput( dw_eigener_thread_id, dw_vordergrund_thread_id, TRUE ) != 0 )
    {
      //Wir haben uns an den ThreadInput von dw_vordergrund_thread_id drangehängt.
      ...
      Code ausführen ( SetFocus(), SendInput(), ... )
      ...
      //Den Attach wieder aufheben.
      AttachThreadInput( dw_eigener_thread_id, dw_vordergrund_thread_id, FALSE );
    }
    else
    {
      //AttachThreadInput ist schief gegangen!
      //Hier Fehlerfall behandeln, z.B. Fehlermeldung...
    }
    

    Vielleicht ist es das?



  • Nein, leider nicht.

    Keiner dieser beiden folgenden Funktionen funktioniert. Es erscheint in beiden Fällen aber auch keine Messagebox. Kann ich also davon ausgehen dass nirgends ein Fehler auftritt?! (Der Unterschied zwischen den beiden folgenden Quellcodes ist nur dass die ersten beiden Parameter der AttachThreadInput(...)-Funktion vertauscht sind).

    Das Notepad-Fenster bekommt den Fokus nicht. Wenn ich Notepad selber anklicke, dann bekommt es die Tastatureingaben, also das 'A'. Oder aber ich ersetze in dem hier dargestellten Quellcode SetFocus(notepadHWND); durch SendMessage(notepadHWND,WM_SETFOCUS,0,0);, wobei es da dann allerdings egal ist, ob ich AttachThreadInput(simulatorThreadId,notePadThreadId,TRUE) oder AttachThreadInput(notePadThreadId,simulatorThreadId,TRUE) aufrufe.

    void simuliereTaste(HWND notepadHWND,HWND smulatorHWND)
    {
    	DWORD notePadProcessId;
    	DWORD simulatorProcessId;
    	DWORD notePadThreadId;
    	DWORD simulatorThreadId;
    	while(1)
    	{
    		Sleep(2000);
    		notePadThreadId = GetWindowThreadProcessId(notepadHWND,&notePadProcessId);
    		simulatorThreadId = GetWindowThreadProcessId(smulatorHWND,&simulatorProcessId);
    		if (AttachThreadInput(notePadThreadId,simulatorThreadId,TRUE) != 0) 
    		{
    			SetFocus(notepadHWND);
    
    			keybd_event(VK_LSHIFT,0,0,0);
    			keybd_event('A',0,0,0);
    			keybd_event('A',0, KEYEVENTF_KEYUP,0);
    			keybd_event(VK_LSHIFT,0, KEYEVENTF_KEYUP,0);
    
    			AttachThreadInput(notePadThreadId,simulatorThreadId,FALSE);
    		}
    		else
    		{
    			MessageBoxA(NULL,"AttachThreadInput fehlgeschlagen","",MB_OK);
    		}
    	}
    }
    
    void simuliereTaste(HWND notepadHWND,HWND smulatorHWND)
    {
    	DWORD notePadProcessId;
    	DWORD simulatorProcessId;
    	DWORD notePadThreadId;
    	DWORD simulatorThreadId;
    	while(1)
    	{
    		Sleep(2000);
    		notePadThreadId = GetWindowThreadProcessId(notepadHWND,&notePadProcessId);
    		simulatorThreadId = GetWindowThreadProcessId(smulatorHWND,&simulatorProcessId);
    		if (AttachThreadInput(simulatorThreadId,notePadThreadId,TRUE) != 0) 
    		{
    			SetFocus(notepadHWND);
    
    			keybd_event(VK_LSHIFT,0,0,0);
    			keybd_event('A',0,0,0);
    			keybd_event('A',0, KEYEVENTF_KEYUP,0);
    			keybd_event(VK_LSHIFT,0, KEYEVENTF_KEYUP,0);
    
    			AttachThreadInput(simulatorThreadId,notePadThreadId,FALSE);
    		}
    		else
    		{
    			MessageBoxA(NULL,"AttachThreadInput fehlgeschlagen","",MB_OK);
    		}
    	}
    }
    


  • Dein Programm sucht ein Fenster von Notepad, findet dieses auch (davon muß ich ausgehen können!).
    Aber Notepad hat nicht unbedingt den Eingabe-Fokus!

    Dein Konstrukt mit AttachThreadInput() an den ThreadInput von Notepad mag zwar funktionieren.
    Doch die Funktionen SetFocus(), SendInput(), usw. können nur dann funktionieren wenn Notepad auch den Fokus hat!

    Wie testest Du das Ganze?
    Es ist ganz wichtig, daß Notepad aktiv UND bereits den Fokus hat!

    Eigentlich müßtest Du mit GetForegroundWindow() das Fenster mit dem aktiven Fokus suchen (das kann ein beliebiges Programm sein), und an dieses Fenster mit AttachThreadInput() anhängen.

    Probiere das mal,
    Martin


  • Mod

    Weiterhin solltest Du das Fenster natürlich auch in den Vordergrund bringen!
    SetForegroundWindow!

    Ansonsten hat das Fenster zwar den Focus, aber bekommt dennoch keine Tastaturinfos, weil die an das Forgroundwindow mit Focus gehen.


Anmelden zum Antworten