Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Come ridimensionare/riposizionare form qualsiasi Windows da codice vba?

143 views
Skip to first unread message

RobertoA

unread,
Oct 5, 2021, 4:28:06 AM10/5/21
to
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?

BFS

unread,
Oct 5, 2021, 5:20:58 AM10/5/21
to

RobertoA

unread,
Oct 5, 2021, 6:12:04 AM10/5/21
to
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?




@Alex

unread,
Oct 5, 2021, 6:29:19 AM10/5/21
to
> 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?

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

RobertoA

unread,
Oct 5, 2021, 8:23:07 AM10/5/21
to
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

@Alex

unread,
Oct 5, 2021, 9:00:51 AM10/5/21
to
> 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

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

RobertoA

unread,
Oct 7, 2021, 4:23:42 AM10/7/21
to
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?

@Alex

unread,
Oct 7, 2021, 4:51:30 AM10/7/21
to
Perché hai dichiarato il più come Integer..?
La guida è chiara... prova ad usare LONG.

@Alex

BFS

unread,
Oct 7, 2021, 5:21:15 AM10/7/21
to
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


BFS

unread,
Oct 7, 2021, 5:33:54 AM10/7/21
to
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

RobertoA

unread,
Oct 7, 2021, 6:08:36 AM10/7/21
to
Provato
Sempre 42 mi ritorna
Parlo dellle righe

Dim pid As Long
pid = ShellExecute(1, "open", "notepad.exe", "", "", 1)
Debug.Print "PID: " & pid

RobertoA

unread,
Oct 7, 2021, 6:14:05 AM10/7/21
to
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



@Alex

unread,
Oct 7, 2021, 7:14:21 AM10/7/21
to
I
> 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

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

BFS

unread,
Oct 7, 2021, 7:39:30 AM10/7/21
to
hai ragione
sembra un valore legato all'applicazione

notepad=42
calcolatrice=2


BFS

RobertoA

unread,
Oct 7, 2021, 7:45:31 AM10/7/21
to
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
0 new messages