Форум » GUI » МиниГуи и чужая программа... » Ответить

МиниГуи и чужая программа...

Andrey: Мне пишут: Возникла необходимость отслеживать окно другой программы (текстовый редактор, просмотрщик PDF) и при необходимости другую программу закрывать. Подобными отслеживаниями, на сколько я знаю, ты занимался. Если можно, короткие выжимки кода для решения данной задачи. Я думаю многим эта тема будет интересна, из-за этого выношу на всеобщий обзор. Кто-нибудь добавит или поправит меня. 1) Для того чтобы управлять другой программой, нужно знать ХЕНДЛ окна этой программы. Как его получить в примерах есть. Вот примерно так я делал: [more][pre2] STATIC lTrayTasks := .f. // нет показа скрытых окон aDim := ListApps() .... /////////////////////////////////////////////////////////////////////////// #define GW_HWNDFIRST 0 #define GW_HWNDLAST 1 #define GW_HWNDNEXT 2 #define GW_HWNDPREV 3 #define GW_OWNER 4 #define GW_CHILD 5 *--------------------------------------------------------* Function ListApps() *--------------------------------------------------------* LOCAL aWindows := {}, cTitle := "", iWindow, cStr, i:=1 LOCAL hWnd := GetWindow( GetForegroundWindow(), GW_HWNDFIRST ) // Get the first window WHILE hWnd != 0 // Loop through all the windows cTitle := GetWindowText( hWnd ) IF GetWindow( hWnd, GW_OWNER ) = 0 .AND.; // If it is an owner window IsWindowVisible( hWnd ) .AND. ; // If it is a visible window !EMPTY( cTitle ) .AND.; // If the window has a title !( "DOS Session" $ cTitle ) .AND.; // If it is not DOS session !( cTitle == "Program Manager" ) // If it is not the Program Manager AADD( aWindows, { hWnd, cTitle, IsWindowVisible( hWnd ) } ) ENDIF hWnd := GetWindow( hWnd, GW_HWNDNEXT ) // Get the next window ENDDO if lTrayTasks hWnd := GetWindow( GetForegroundWindow(), GW_HWNDFIRST ) WHILE hWnd != 0 // Loop through all the windows cTitle := GetWindowText( hWnd ) IF GetWindow( hWnd, GW_OWNER ) = 0 .AND.; // If it is an owner window !IsWindowVisible( hWnd ) .AND.; // If it is a visible window !EMPTY( cTitle ) .AND.; // If the window has a title !( "MS_" $ cTitle ) .AND.; // If it is not System apps !( "DDE" $ cTitle ) .AND.; // If it is not System apps !( "SYSTEM" $ cTitle ) .AND.; // If it is not System apps !( "SENS" $ cTitle ) .AND.; // If it is not System apps !( "WIN95" $ cTitle ) .AND.; // If it is not System apps !( "Spooler" $ cTitle ) .AND.; // If it is not System apps !( "Thread" $ cTitle ) .AND.; // If it is not System apps !( "DOS Session" $ cTitle ) .AND.; // If it is not DOS session !( cTitle == "Program Manager" ) // If it is not the Program Manager AADD( aWindows, { hWnd, cTitle, IsWindowVisible( hWnd ) } ) ENDIF hWnd := GetWindow( hWnd, GW_HWNDNEXT ) // Get the next window ENDDO endif // отладка в файл cStr := "" FOR iWindow := 1 TO LEN(aWindows) cStr += STR(iWindow,3)+";"+STR(aWindows[iWindow,1])+"; "+aWindows[iWindow,2] + CRLF NEXT hb_memowrit( ChangeFileExt( Application.ExeName, ".log" ), cStr ) Return aWindows [/pre2] [/more] 2) Закрыть чужое окно примерно так: [pre2]#define WM_CLOSE 0x0010 #define WM_DESTROY 0x0002 .... lAsk2Save := ??? PostMessage( iWindow, IF(lAsk2Save, WM_CLOSE, WM_DESTROY), 0, 0 ) // Close the window DO EVENTS[/pre2] Только я уже не помню разницу между WM_CLOSE и WM_DESTROY Давно делал в 2014 году ещё...

Ответов - 5

Dima: Andrey пишет: Только я уже не помню разницу между WM_CLOSE и WM_DESTROY гугл помнит

SergKis: Не давно делал для получения hWnd[pre2] *-----------------------------------------------------------------------------* STATIC FUNCTION HandlesDosBox() *-----------------------------------------------------------------------------* LOCAL h, t LOCAL cText := 'DOSBox ' LOCAL aDBox := {} LOCAL aRet := {} AEVal( EnumWindows(), {|hw| iif( GetClassName(hw) == "SDL_app", AAdd( aDBox, hw ), Nil )} ) FOR EACH h IN aDBox t := GetWindowText( h ) IF cText $ t /* .and. upper( cText ) $ t */ ; AAdd( aRet, h ) ENDIF NEXT RETURN aRet *-----------------------------------------------------------------------------* STATIC FUNCTION HandlesHbWin( cText, cClass, lLogOut ) *-----------------------------------------------------------------------------* LOCAL i, h, t LOCAL aWnd := EnumWindows() LOCAL aTmp := {} LOCAL aRet := {} IF empty(cClass) ; aTmp := aWnd ELSE ; AEVal(aWnd, {|hw| iif( GetClassName(hw) == cClass, AAdd( aTmp, hw ), )}) ENDIF IF ! empty(cText) .and. HB_ISCHAR(cText) .and. Len(aTmp) > 0 FOR EACH h IN aTmp t := GetWindowText( h ) IF cText $ t ; AAdd( aRet, h ) ENDIF NEXT ELSE aRet := aTmp ENDIF IF ! Empty(lLogOut) FOR i := 1 TO Len(aTmp) t := GetWindowText(aTmp[ i ]) MsgLog( str(i, 5), aTmp[ i ], GetClassName(aTmp[ i ]), t ) NEXT ENDIF RETURN aRet Использование для DosBox LOCAL aAll := HandlesDosBox() LOCAL nAll := Len(aAll) ... _Execute( 0, , cRun, '-conf dosbox.conf -noconsole', cPath ) hTmp := nJ := nW := 0 ; wApi_Sleep(50) FOR nI := 1 TO 11 // опр. новый handle DosBox nW := 50 If nI > 2 nJ ++ nW := nWait EndIf wApi_Sleep( nW ) oMain:StatusBar:Say( cWait + ' ' + iif( nJ > 0, hb_ntos( nJ ), '' ) ) aTmp := HandlesDosBox() IF ( nTmp := Len( aTmp ) ) > 0 IF nAll > 0 FOR nK := 1 TO nTmp nN := AScan( aAll, aTmp[ nK ] ) IF nN == 0 hTmp := aTmp[ nK ] EXIT ENDIF NEXT ELSE hTmp := ATail( aTmp ) ENDIF ENDIF IF ! empty( hTmp ) ; EXIT ENDIF NEXT oMain:StatusBar:Say( '' ) IF ! empty( hTmp ) // нашли row := This.&(cName).Cargo [ DOSBOX_ROW ] col := This.&(cName).Cargo [ DOSBOX_COL ] nRow := iif( Empty(row), nRow, row ) nCol := iif( Empty(col), nCol, col ) width := GetWindowWidth (hTmp) height := GetWindowHeight(hTmp) MoveWindow ( hTmp , nCol , nRow , width , height , .T. ) // меняем позицию окна DosBox (как ставили при пред. запуске) This.&(cName).Cargo [ DOSBOX_HANDLE ] := hTmp This.&(cName).Cargo [ DOSBOX_ROW ] := nRow This.&(cName).Cargo [ DOSBOX_COL ] := nCol This.&(cName).Cargo [ DOSBOX_SEND ] := cSend This.&(cName).Cargo [ DOSBOX_RECV ] := cRecv This.&(cName).Cargo [ DOSBOX_KOD ] := cKod This.&(cName).Enabled := .F. This.Dos.Enabled := .T. DO EVENTS ENDIF (ThisWindow.Object):Action := .T. ... На таймере висит ф-я, определяющая команды от DosBox на запуск wvt или hmg программ цветом использование ф-ий выше указанных *----------------------------------------------------------------------------* STATIC FUNCTION Timer_IsDosBoxHandle() *----------------------------------------------------------------------------* LOCAL aTmp, cItm, aMnu, nN, nI := 0, nK, nH, nP LOCAL nDos := 0, aDos, hDos, cStr, cTitl, cClNm LOCAL cTxt := '', cSend, hWvt, aWvt, lBlk LOCAL aFil := {}, cRecv, cExe, cPar, nHmg, hHmg LOCAL cFil, nRow, nCol, cIni, cKod, cDrv, cMount LOCAL cDir, cBlk, cRun, cDsk, cPll, cPath LOCAL cSpooler, cFilePrn, cFun, cMsg, cWait, lWait This.Dos.Enabled := .F. WITH OBJECT oMain:Cargo cPath := :cDosBoxPath // :cCurDir = C:\DosBox cMount := upper( :cDosBoxBase ) // Mount cFil := :cHbkIniDat cPll := :cPll cSpooler := :cPll + 'SPOOLER' + '\' cFilePrn := :cPll + 'FILEPRN' + '\' END WITH aMnu := ThisWindow.Cargo:Menu aDos := HandlesDosBox() FOR EACH cItm IN aMnu nI ++ aTmp := This.&(cItm).Cargo hDos := aTmp [ DOSBOX_HANDLE ] // handle DosBox window nRow := aTmp [ DOSBOX_ROW ] nCol := aTmp [ DOSBOX_COL ] cSend := aTmp [ DOSBOX_SEND ] cRecv := aTmp [ DOSBOX_RECV ] cKod := aTmp [ DOSBOX_KOD ] hWvt := aTmp [ DOSBOX_WVT ] lBlk := aTmp [ DOSBOX_BLK ] IF ! empty( hDos ) IF ( nN := AScan( aDos, hDos ) ) == 0 hDos := hWvt := 0 cSend := cRecv := cKod := '' This.&(cItm).Enabled := .T. ELSE nDos += 1 nRow := GetWindowRow( hDos ) nCol := GetWindowCol( hDos ) ENDIF DO EVENTS ENDIF This.&(cItm).Cargo [ DOSBOX_HANDLE ] := hDos This.&(cItm).Cargo [ DOSBOX_ROW ] := nRow This.&(cItm).Cargo [ DOSBOX_COL ] := nCol This.&(cItm).Cargo [ DOSBOX_SEND ] := cSend This.&(cItm).Cargo [ DOSBOX_RECV ] := cRecv This.&(cItm).Cargo [ DOSBOX_KOD ] := cKod If ! empty(hDos) cIni := cSend+cItm+'.ini' cBlk := cSend+cItm+'.blk' cMsg := cSend+cItm+'.msg' lBlk := ! empty(lBlk) If hb_FileExists( cIni ) wApi_Sleep(200) lBlk := hb_FileExists( cBlk ) cTitl := gIniC7( cIni, [RUN], 'Txt' , '' ) cClNm := gIniC7( cIni, [RUN], 'Cln' , '' ) cDrv := gIniC7( cIni, [RUN], 'Drv' , '' ) cDir := gIniC7( cIni, [RUN], 'Ctl' , '' ) cRun := gIniC7( cIni, [RUN], 'Run' , '' ) cWait := gIniC7( cIni, [RUN], 'Wait', 'Y' ) lWait := 'Y' $ upper(cWait) fErase( cIni ) If ! empty(cDir) .and. ! empty(cRun) nK := At(' ', cRun) cExe := Left(cRun, nK-1) cDsk := iif( empty(cDsk), '""', cDsk ) cPar := Trim(Subs(cRun, nK+1))+' '+cMsg hWvt := nHmg := 0 IF lower(right(cExe, 4)) == '.fun' cFun := left(cExe, RAt('.', cExe)-1) If lower(cFun) == 'copy_to' ; Copy_To (cMount, cDrv, cPar) ElseIf lower(cFun) == 'copy_from' ; Copy_From(cMount, cDrv, cPar) ElseIf lower(cFun) == 'copy_file' ; Copy_File(cMount, cDrv, cPar) EndIf fErase( cBlk ) lBlk := .F. ELSEIF lower(right(cExe, 4)) == '.prg' .or. lower(right(cExe, 4)) == '.hrb' ELSE IF hb_FileExists(cExe) If lWait aWwt := HandlesHbWin(cTitl, cClNm) oMain:Minimize() DO EVENTS ENDIF nHmg := _ExecuteEx( 0, , cExe, cPar, cDir ) // это ShellExecuteEx(...) wApi_Sleep(1000) DO EVENTS IF lWait IF cClNm == WVT_CLASS_NAME ; wApi_Sleep(1000) ENDIF If ! Empty(nHmg) FOR EACH nH IN HandlesHbWin(cTitl, cClNm) IF ( nP := AScan(aWvt, nH) ) == 0 hWvt := nH EXIT ENDIF NEXT EndIf DO EVENTS ELSE fErase( cBlk ) ENDIF ELSE MsgBox('File not found !'+CRLF+cExe, 'Info-'+cItm) fErase( cBlk ) ENDIF ENDIF EndIf ElseIf lBlk IF ! empty(hWvt) .and. hb_FileExists( cBlk ) IF Empty( AScan( HandlesHbWin(), hWvt ) ) fErase( cBlk ) wApi_Sleep(200) ENDIF ENDIF IF ! hb_FileExists( cBlk ) wApi_Sleep(200) oMain:Restore() DO EVENTS lBlk := .F. hWvt := 0 BringWindowToTop( hDos ) DO EVENTS ENDIF EndIf EndIf This.&(cItm).Cargo [ DOSBOX_WVT ] := hWvt This.&(cItm).Cargo [ DOSBOX_BLK ] := ! empty(lBlk) AAdd( aFil, { cItm, hDos, nRow, nCol, cSend, cRecv, cKod, hWvt, lBlk } ) NEXT hb_memowrit( cFil, hb_valtoexp( aFil ) ) IF nDos > 0 cTxt := chr(9)+hb_ntos(nDos) This.Dos.Enabled := .T. ENDIF oMain:StatusBar:Say( cTxt, 3) oMain:Cargo:nDosBoxRun := Val( cTxt ) RETURN Nil ... [/pre2] Для MiniGui имя окна MAIN является именем класса, т.е. правильно называя main окна, можно находить по нему нужное окно hWnd для hmg

Vlad04: Ок Спасибо, ищет, закрывает


Vlad04: Ещё надо отследить закрылась или нет чужая программа. Конечно, можно, по выше указанному алгоритму - если исчезла программа, значит закрылась. Но может ак-то короче.

SergKis: Vlad04 пишет Но может ак-то короче. Если имеете текст заголовка, то ищете по нему, подождав к примеру wApi_Sleep(500) после посылки сообщения на закрытие. Если несколько экземпляров этой программы, то по handle ищем, кому было сообщение на закрытие или по алгоритму



полная версия страницы