SendMessage() & Co funktionieren nicht


  • 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.



  • Ok, so funktioniert es (jetzt auch ohne Unsitte 😉 ).
    SetForegroundWindow(notepadHWND); hat gefehlt.
    Vielen Dank euch beiden!!!

    Aber wichtig:
    SetForegroundWindow(notepadHWND); muss vor AttachThreadInput(notePadThreadId,simulatorThreadId,TRUE) stehen

    Übrigens fünktioniert es auch ohne SetFocus(notepadHWND); - aber erst einen Zyklus später, also beim zweiten Durchgang der while()-Schleife.

    void simuliereTaste(HWND notepadHWND,HWND smulatorHWND)
    {
    	HANDLE h = (HANDLE)p;
    	DWORD notePadProcessId;
    	DWORD simulatorProcessId;
    	DWORD notePadThreadId;
    	DWORD simulatorThreadId;
    	while(1)
    	{
    		Sleep(2000);
    
    		notePadThreadId = GetWindowThreadProcessId(notepadHWND,&notePadProcessId);
    		simulatorThreadId = GetWindowThreadProcessId(smulatorHWND,&simulatorProcessId);
    		SetForegroundWindow(notepadHWND);	
    		AttachThreadInput(notePadThreadId,simulatorThreadId,TRUE)
    		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);
    	}
    }
    

    Trotzdem werde ich das Gefühl nicht los, auf der falschen Fährte zu sein.
    Gehe ich richtig in der Annahme, dass es keine andere Möglichkeit gibt,
    einem (fremden) Programm Maus- und Tastatur-Inputs zu senden - ohne dass es sich im Vordergrund befindet?

    Desweiteren würde ich gerne die Pixel des Empfängerprogramms auslesen.
    Das ist soweit möglich, jetzt wo das Fenster im Vordergrund ist. Aber geht das auch bei minimierten Fenstern oder Fenstern, die im Hintergrund sind?

    MfG


Anmelden zum Antworten