Ist es mit c++ möglich ein bereits installiertes Programm zu steuern Screenreader



  • Hallo ich möchte einen Art Screenreader nutzen der Buttons und Knöpfe eines installierten Programms erkennt und steuert.(Mit der Maus) Ist sowas möglich ? und wie?
    Könnt ihr mir Tipps geben ?



  • Was genau hast du denn vor? Ist das Userinterface was du steuern willst etwa dynamisch? Wenn es statisch ist, könntest du die MausClicks immer an einer bestimmten Stelle simulieren, wenn du weißt dass dort ein Button ist.

    Und natürlich kannst du einen Screenshot machen ( mittels Quellcode ) und dann per neuronalem Netz die Buttons erkennen und dort einen Mausclick platzieren. Ich habe aber Zweifel dass es sowas schon vorgefertigt gibt. Da wirst du dich selber einarbeiten müssen.



  • Es gibt Software die ähnliches macht, ich kenne die vor allem aus dem Testing bereich. Die haben einen Inspektor der Informationen zu den einzelenen Objekten bereitstellt und übder diese kann man die dann ansprechen. Daher sollte auch sowas wie du vor hast, irgendwie zu lösen sein.

    Ich habe mich noch nicht mit der Entwicklung solcher Programme beschäftigt, würde aber (wenn wir von Windows reden) mal einen Blick in die WinApi riskieren. Es gibt FindWindow Funktionen (welche du davon gebrauchen kannst, weiß ich nicht) und eine SendInput() Funktion. Damit könntest du evt. starten.


  • |  Mod

    Schau Dir SendInput an.

    Das hat allerdings kaum etwas mit C++/CLI zu tun.



  • Soweit ich weiss wird für Dinge dieser Art oft AutoIt verwendet. Vielleicht solltest du dir das mal ansehen.



  • du kannst das programm mittels PostMessage ansteuern.

    vor vielen jahren ("damals") gab es die möglichkeit, sich über irgendein programm irgendwelche werbebanner auf den desktop zu ziehen und wenn man die 10 mal oder so angeklickt hat, gabs 5 ct.

    weil man natürlich noch was anderes zu tun hatte, als sich den ganzen tag werbung anzugucken, haben schlaue leute dann ein programm entwickelt, welches die maus immer bewegt und diese werbebanner angewählt hat, und sowas geht unter anderem mit PostMessage und WM_MOUSEMOVE und WM_LBUTTONDOWN.



  • Hi,

    wenn du die Koordinaten der Elemente über die Analyse deines Screenshots erhoben hast, zb über einen Offset. Kannst Du Dir eine Automaus über einen Timer gestalten:

     ... Code ... 
    void Klick(int x, int y)
    {
    	::SetCursorPos(x, y);
    	Sleep(10);
    	mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0); Sleep(10);
    	mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0); Sleep(10);
    	mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0); Sleep(10);
    	mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0); Sleep(10);
    }
    

    Dito für das Kyboard:

     ... Code ... 
    keybd_event(VK_ESCAPE ,0x041,0 , 0);
    

    Auf den Prozessmemory kannst Du auch zugreifen via PseudoCode:

     ... Code ... 
    
    DWORD CWotBotDlg::ReplaceProcessMem(char *pProcessName,BYTE *pSerchMem, BYTE *pReplaceMem, DWORD pReplaceLen)
    {
    	BYTE        *pMem        = 0,
    		        *pFind       = 0;
    	LPVOID		lpMem        = 0;  
    	DWORD       nChange      = 0,
    		        nlastchange  = 0,
    	            nBytesRead   = 0,
    		        ProcessID    = FindProcess(pProcessName,0);
    	HANDLE      hProcess     = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);
    	SYSTEM_INFO	si; GetSystemInfo(&si);
    	MEMORY_BASIC_INFORMATION mbi;
    
    	m_AdrPage.clear();
    
    	NtSuspendProcess pfnNtSuspendProcess = (NtSuspendProcess)GetProcAddress(GetModuleHandle("ntdll"), "NtSuspendProcess");
    	NtResumeProcess  pfnNtResumeProcess  = (NtSuspendProcess)GetProcAddress(GetModuleHandle("ntdll"), "NtResumeProcess");
    
    	pfnNtSuspendProcess(hProcess);
    
    	for(DWORD pagecnt = 0; lpMem < si.lpMaximumApplicationAddress; pagecnt++)
    	{
    	  VirtualQueryEx(hProcess,lpMem,&mbi,sizeof(MEMORY_BASIC_INFORMATION));
    
    	  if(!((mbi.State == MEM_FREE)||(mbi.State == MEM_RESERVE)||(mbi.Protect & PAGE_WRITECOPY)||
    	      (mbi.Protect & PAGE_EXECUTE)||(mbi.Protect & PAGE_GUARD)||(mbi.Protect & PAGE_NOACCESS))) 
    		
    		
    		//if (pagecnt == 352)
    		if( (DWORD)mbi.BaseAddress == 230686724) //MIND 349,352  adr=230686720
    		if((pMem = (BYTE *)VirtualAlloc(0,mbi.RegionSize,MEM_COMMIT,PAGE_READWRITE)))
    		{
    		  if(ReadProcessMemory(hProcess,mbi.BaseAddress,pMem,mbi.RegionSize,&nBytesRead))
    		   
    			if((pFind = FindMem(pMem,pSerchMem,nBytesRead,4)))
    			{
    			     memcpy(pFind,pReplaceMem,pReplaceLen);
    
    				 //only write target byte ? Please test it out ! WriteProcessMemory(hProcess, mbi.BaseAddress, pFind, 4, &nBytesRead);
    
    			     WriteProcessMemory(hProcess, mbi.BaseAddress, pMem, mbi.RegionSize, &nBytesRead);
    			 
    				  ADRPAGE adr;
    
    				  adr.adress = (DWORD)mbi.BaseAddress;
    				  adr.page   = (DWORD)pagecnt;
    				  m_AdrPage.push_back(adr);
    			      nChange++;
    				  CString str; str.Format("\r\nPage(%d)  Adr(%d)\r\n", (DWORD)pagecnt, (DWORD)mbi.BaseAddress);
    				  TRACE(str);
    				  //AfxMessageBox(str);
    			 
    			}
    			  
    		  VirtualFree(pMem, mbi.RegionSize, MEM_DECOMMIT);
    		}
    
    	  lpMem = (LPVOID)((DWORD)mbi.BaseAddress + (DWORD)mbi.RegionSize);
    	}
    
    	pfnNtResumeProcess(hProcess);
    
    	CloseHandle(hProcess);
    
      return nChange;
    }
    

    Eine Liste der laufenden Prozesse kannst Du auch abgreifen:

     ... Code ... 
    DWORD FindProcess(char *pName,int prcnt/*=0*/)
    {
    	typedef HANDLE (WINAPI *PFN_CREATETHELP32SNPSHT)(DWORD,DWORD);
    	typedef BOOL   (WINAPI *PFN_PROCESS32FIRST)(HANDLE,PROCESSENTRY32*);
    	typedef BOOL   (WINAPI *PFN_PROCESS32NEXT)(HANDLE,PROCESSENTRY32*);
    	
    	PFN_CREATETHELP32SNPSHT fnCreateToolhelp32Snapshot;
    	PFN_PROCESS32NEXT fnProcess32Next;
    	PFN_PROCESS32FIRST fnProcess32First;
    
    	HMODULE hWin95Kernel = GetModuleHandle("kernel32.dll");
    	if(!hWin95Kernel) 
    	  return 0;
    
    	if(!(fnCreateToolhelp32Snapshot=(PFN_CREATETHELP32SNPSHT)GetProcAddress(hWin95Kernel,"CreateToolhelp32Snapshot")) )
    	  return 0;
    	if(!(fnProcess32First=(PFN_PROCESS32FIRST)GetProcAddress(hWin95Kernel,"Process32First")) )
    	  return 0;
    	if(!(fnProcess32Next=(PFN_PROCESS32NEXT)GetProcAddress(hWin95Kernel,"Process32Next")) )
    	  return 0;
    
    	PROCESSENTRY32 process;process.dwSize=sizeof(PROCESSENTRY32);
    	HANDLE handle = fnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    	if(!handle) return 0;
    
    	int n=0;fnProcess32First(handle,&process);
    	do
    	{
    	 if(!strncmp(process.szExeFile,pName,strlen(pName)))
    	  if(n++ >= prcnt) return process.th32ProcessID;
    	}while(fnProcess32Next(handle,&process));
    	
    	return 0;
    }
    

    Auf den Desktop kannst Du selbst screenshots herstellen um auf die Bitmap zu kommen:

    PseudoCode:

     ... Code ... 
    CWnd* pClientWnd=(FindWindow(0,"ClientWinName"));
    	if(!pClientWnd) return;
    
    	CDC*  pDC(pClientWnd->GetWindowDC()); 
    	CRect rcClient;pClientWnd->GetClientRect(&rcClient);
    	CRect rc;GetClientRect(&rc);
    
    	int     th        = ::GetSystemMetrics(SM_CYCAPTION); //titelbar
    	int     mh        = ::GetSystemMetrics(SM_CYMENU); //menubar
    	int     bw        = ::GetSystemMetrics(SM_CXFIXEDFRAME)<<1;//border
    	int     nWidth    = rc.Width();//GetSystemMetrics(SM_CXFULLSCREEN);
    	int     nHeight   = rc.Height();//GetSystemMetrics(SM_CYFULLSCREEN);
    	HDC     hdcMem    = ::CreateCompatibleDC(pDC->m_hDC);
    	HBITMAP hbm       = ::CreateCompatibleBitmap(pDC->m_hDC, nWidth, nHeight);
    	HBITMAP hbmOld    = (HBITMAP)::SelectObject(hdcMem, hbm);
    	
    	::SetStretchBltMode(dc.m_hDC,STRETCH_DELETESCANS);//stretch with highquality
    	::StretchBlt(/*m_dib.GetDC()*/dc.m_hDC, 0,0, rc.Width(), rc.Height(),pDC->m_hDC , bw, th+bw,rcClient.Width()-bw,rcClient.Height(),SRCCOPY);
    	//BitBlt(hdcMem, 0, 0, nWidth, nHeight, pDC->m_hDC, 0, 0, SRCCOPY);
    	::SetStretchBltMode(hdcMem,STRETCH_DELETESCANS);//stretch with highquality
    	::StretchBlt(hdcMem, 0,0, rc.Width(), rc.Height(),pDC->m_hDC , bw, th+bw,rcClient.Width()-bw,rcClient.Height(),SRCCOPY);
    
    	BITMAPINFO bmi;ZeroMemory(&bmi, sizeof(bmi));
    	bmi.bmiHeader.biSize         = sizeof(BITMAPINFOHEADER);
    	bmi.bmiHeader.biWidth        = nWidth;
    	bmi.bmiHeader.biHeight       = -nHeight;
    	bmi.bmiHeader.biBitCount     = 24;
    	bmi.bmiHeader.biPlanes       = 1;
    	bmi.bmiHeader.biCompression  = BI_RGB;
    	bmi.bmiHeader.biSizeImage    = nWidth * nHeight * 3;
     
    	BYTE *pbBits = new BYTE[bmi.bmiHeader.biSizeImage];
    	::GetDIBits( hdcMem, hbm,0,abs(bmi.bmiHeader.biHeight),pbBits,&bmi,DIB_RGB_COLORS );
    	
    	    BYTE red1;
    		BYTE green1;
    		BYTE blue1;
    		COLORREF rgb = TestRegion(266, 17, 96 ,22, nWidth, pbBits);
    		//garage
    		red1   = GetRValue(rgb);
    		green1 = GetGValue(rgb);
    		blue1  = GetBValue(rgb);
    		TRACE("(A) %d:%d:%d\r\n",red1,green1,blue1);
    
    		/*
    		if(red1 > 77 && red1 < 83 && green1 > 33 && green1 < 41 &&  blue1 > 22 && blue1 < 29 && g_state == 0)//oben ja
    		{
    		   int x(511),y(76);
    		   SetCursorPos(x,y);Sleep(10);
    
    		   mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);Sleep(10);
    		   mouse_event(MOUSEEVENTF_LEFTUP,x,y,0,0);Sleep(10);
    		   keybd_event(VK_ESCAPE ,0x041,0 , 0);
    		   g_state = 1;
    		}
    		*/
    
    	
    
    	//CString str; str.Format("%d.bmp",n++);
    	//m_dib.Save(str.GetBuffer(),pbBits);//dc.SelectObject(pOldBmp);
    
        delete [] pbBits;
     
    	::SelectObject(hdcMem, hbmOld);
    	::ReleaseDC(0, pDC->m_hDC);
    	::ReleaseDC(0, hdcMem);
    

    Grüße
    Karsten