Newsgroup: it.comp.appl.access
Titolo: Come ridimensionare/riposizionare form qualsiasi Windows da codice vba?

Sto tentando, da codice vba, di avviare Anydesk indicando un certo Id 
dispositivo sul quale collegarsi
Una roba del tipo
c:\programmi\anydesk.exe 123456789
E parte tutto correttamente, come atteso
Ma parte dove vuole lui e grande quanto vuole lui
Ravanando nel sito del produttore trovo che i comandi per dimensionare 
la finestra appena avviata e posizionarla dove si desidera , sarebbero 
anche previsti, ma solo come opzioni per il 'client custom'
 
https://support.anydesk.com/Custom_Client_Advanced_Options#Position_and_size_of_the_window
 
 
Io vorrei invece fare tutto da codice vba, quindi lanciare il 
collegamento col client, dimensionare come pare a me, posizionare dove 
pare a me
Obiettivo del tutto e' aprire contemporaneamente il collegamento su 6-8 
postazioni remote e tenerle sotto controllo tutte insieme
Da parametro su riga comando avvio, pare non si possa (se si potesse 
ditemelo pero')
Allora ho pensato, "e io ti sparo il comando da esterno"
Avendo l'handle della finestra apena aperta, credo sia possibile dargli 
posizione e dimensione
Bon, fin qua' ho lavorato io
Adesso pero' datemi una mano voi :) :) :)
Come l'e' che si fa?


vedi se questo aiuta
 
 
https://renenyffenegger.ch/notes/development/languages/VBA/Win-API/examples/SetWindowPos/index
 
 
 
BFS


E gia' e' proprio questo che cercavo
Mi mancava la FindWindows per acchiappare l'handle di una finestra
Vedo pero' che vuole il 'class name' della finestra
E quindi ora il problema si sposta su:
- data una qualsiasi windows form visibile a schermo, come recuperarne 
il class name?
 
 
 
 

 il class name?
 
Quali Elementi CERTI hai per individuare una WindowsForm..?
 
Se la Form di cui parli è ONTOP, usa un'altro metodo:
Handle=WindowFromPoint(P)
Dove P è il Type PointAPI, e puoi assegnare un X/Y o GetCursorPos(P), in questo caso ricavi l'Handle della Window sotto il Mouse.
 
Se non hai elementi non trovi l'Handle di nulla... perchè anche Ciclare o Enumerare le WondowsForm aperte e visibili, non serve se poi non la sai individuare con qualche proprietà.
 
@Alex


Lo ShellExecute che uso per avviare il programma estrno, non puo' 
restituirmi qualcosa di buono per poi identificarlo tra le altre varie 
windows?
Oppure andiamo col titolo, ma quello si sa, puo' essere duplicato

 Oppure andiamo col titolo, ma quello si sa, puo' essere duplicato
 
Certo che si... 
Come indicato dalla GUIDA:
https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutea
 
 
ShellExecute, restituisce l'istanza del Processo lanciato, o ProcessID o PID dell'applicazione lanciata.
Da quello enumerando le Windows e confrontando per ognuna il suo Pid si può determinare l'Hwnd del Pid incriminato con GetWindowThreadProcessId
 
Eccolo 2 esempi:
https://forums.codeguru.com/showthread.php?446691-RESOLVED-How-to-get-handle-of-main-form-using-ProcessID
 
oppuyre:
https://www.vbforums.com/showthread.php?262384-window-handle-from-process-id
 
 
@Alex


La ShellExecute mi restituisce sempre 42
Anche se ne metto tre di fila, sempre 42
Il codice che uso e'
 
Dim pid As Integer, pid2 As Integer
pid = ShellExecute(1, "open", exe_mio, parametri_per_exe, "", 1)
 
Ma non dovrebbe ritornarmi il ProcessID dell'applicazione avviata?
Forse sbaglio a lanciare la ShellExecute?
 

Perché hai dichiarato il più come Integer..?
La guida è chiara... prova ad usare LONG.
 
@Alex


questo link che ti ha postato alex funziona perfettamente per ricavare 
handle dal id
 
https://www.vbforums.com/showthread.php?262384-window-handle-from-process-id
 
 
appena provato
ciao
 
 


usando i link postati da alex con questo codice apri il note pad e lo 
piazzi in alto sx con 500 di larghezza e 500 di altezza
 
 
in un modulo pubblico metti (modifica se 64bit)
 
     Declare Function SetWindowPos Lib "user32" ( _
     ByVal hwnd As Long, _
     ByVal hWndInsertAfter As Long, _
     ByVal x As Long, _
     ByVal y As Long, _
     ByVal cx As Long, _
     ByVal cy As Long, _
     ByVal wFlags As Long) As Long
 
 
 
 
 
crea una maschera con un pulsante
 
su click del pulsante metti
 
Dim Pid As Long
         'Lock the window update
         LockWindowUpdate GetDesktopWindow
         'Execute notepad.Exe
         Pid = Shell("c:\windows\notepad.exe", vbNormalFocus)
         If Pid = 0 Then MsgBox "Error starting the app"
         'retrieve the handle of the window
         mWnd = InstanceToWnd(Pid)
         Debug.Print mWnd
         'Set the notepad's parent
    '     SetParent mWnd, Me.hwnd
         'Put the focus on notepad
         'Putfocus mWnd
         'Unlock windowupdate
     '    LockWindowUpdate False
 
         SetWindowPos mWnd, 0, 0, 0, 500, 500, 0
 
 
 
nel codice maschera:
 
 
     Private Declare Function FindWindow Lib "user32" Alias 
"FindWindowA" (ByVal lpClassName As Long, ByVal lpWindowName As Long) As 
Long
     Private Declare Function GetParent Lib "user32" (ByVal hwnd As 
Long) As Long
     Private Declare Function SetParent Lib "user32" (ByVal hWndChild As 
Long, ByVal hWndNewParent As Long) As Long
     Private Declare Function GetWindowThreadProcessId Lib "user32" 
(ByVal hwnd As Long, lpdwProcessId As Long) As Long
     Private Declare Function GetWindow Lib "user32" (ByVal hwnd As 
Long, ByVal wCmd As Long) As Long
     Private Declare Function LockWindowUpdate Lib "user32" (ByVal 
hwndLock As Long) As Long
     Private Declare Function GetDesktopWindow Lib "user32" () As Long
     Private Declare Function DestroyWindow Lib "user32" (ByVal hwnd As 
Long) As Long
     Private Declare Function TerminateProcess Lib "kernel32" (ByVal 
hProcess As Long, ByVal uExitCode As Long) As Long
     Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
     Private Declare Function Putfocus Lib "user32" Alias "SetFocus" 
(ByVal hwnd As Long) As Long
     Const GW_HWNDNEXT = 2
     Dim mWnd As Long
 
 
 
 
 
     Function InstanceToWnd(ByVal target_pid As Long) As Long
         Dim test_hwnd As Long, test_pid As Long, test_thread_id As Long
         'Find the first window
         test_hwnd = FindWindow(ByVal 0&, ByVal 0&)
         Do While test_hwnd <> 0
             'Check if the window isn't a child
             If GetParent(test_hwnd) = 0 Then
                 'Get the window's thread
                 test_thread_id = GetWindowThreadProcessId(test_hwnd, 
test_pid)
                 If test_pid = target_pid Then
                     InstanceToWnd = test_hwnd
                     Exit Do
                 End If
             End If
             'retrieve the next window
             test_hwnd = GetWindow(test_hwnd, GW_HWNDNEXT)
         Loop
     End Function
     Private Sub Form_Unload(Cancel As Integer)
         'Unload notepad
         DestroyWindow mWnd
         'End this program
         TerminateProcess GetCurrentProcess, 0
     End Sub
 
 
 
testato e funziona
BFS


Provato
Sempre 42 mi ritorna
Parlo dellle righe
 
Dim pid As Long
pid = ShellExecute(1, "open", "notepad.exe", "", "", 1)
Debug.Print "PID: " & pid


Si, certo, l'esempio consigliato da Alex  funziona
Questo pero' usa SHELL per avviare il programma
E la SHELL ritorna correttamente un valore che poi passato alla 
InstanceToWnd ti restituisce l'hWnd da usare per la SetWindowsPos
Io ho sempre provato con la ShelExecute e li mi fermavo perche' non 
restituisce l'Hinstance o se la restituisce e' sempre lo stesso numero, 
42, strana questa cosa
 
 
 

 42, strana questa cosa
 
Nonostante la guida indichi che ShellExecute restituisce l'istanza, pare non sia così in effetti...
Serve usare ShellExecuteEx per avere l'istanza, come riportato qui:
 
https://docs.microsoft.com/it-it/windows/win32/api/shellapi/nf-shellapi-shellexecuteexa?redirectedfrom=MSDN
 
 
In ognincaso con shell  funziona penso sia più comodo e di semplice implementazione.
 
@Alex


hai ragione
sembra un valore legato all'applicazione
 
notepad=42
calcolatrice=2
 
 
BFS
 


Certo, se la Shell lancia il programma e restituisce il pid e' perfetta
 
Un'altra cosa davvero cusiosa
La InstanceToWnd, come da esempi sopra, mi tornava sempre 0
Controlla di qua, controlla di la', era la FindWindows al suo interno 
che ritornava sempre 0 e quindi usciva subito dalla funzione
 
Controllo il Declare della FindWindow e sembra tutto a posto, due long 
come parametri e torna un valore anch'esso long
Do' un'occhiata su internet e salta fuori che in molti siti la 
FindWindows ha il declare cosi
 
Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal 
lpClassName As string, ByVal lpWindowName As string) As Long
 
Con due stringhe come parametri, non due long
Cambio anch'io, e cambio anche la riga dentro la InstanceToWnd  da
test_hwnd = FindWindow(ByVal 0&, ByVal 0&)
in
test_hwnd = FindWindow(vbNullString, vbNullString)
 
Eeee.. resta d stucco e' un barbatrucco, ora funziona come previsto
 
Ma che e'? Neanche piu' delle Api possiamo fidarci?
Iniziano a pungerci pure loro?
Qua' vien giu' un pilastro dell'informatica microsoftiana