PDA

Ver la Versión Completa : [Compilador] Processo/EXE ativo


Joseg
5 de noviembre de 2024, 16:51
Olá

Como saber en Powercobol se um processo esta ativo?

Gracias
Jose

fastpho
5 de noviembre de 2024, 21:11
Hola @Joseg , si estas buscando saber si una appxxx.exe esta ejecutandose dos formas :
una con el control ocx ScriptControl


ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 scriptCode1 pic x(500).
PROCEDURE DIVISION.
MOVE SPACES TO scriptCode1.
string
'Sub MYProgram() ' vbCRLF
' Set objWMI = GetObject("winmgmts:\.
ootcimv2")' vbCRLF
' Set colProcesses = objWMI.ExecQuery("SELECT * FROM Win32_Process WHERE Name = ""ElsisGestion.exe"" ") ' vbCRLF
' If colProcesses.Count = 0 Then' vbCRLF
' MsgBox "El programa no se está ejecutando"' vbCRLF
' Else' vbCRLF
' MsgBox "El programa se está ejecutando"' vbCRLF
' End If' vbCRLF
'End Sub' vbCRLF
delimited by size into scriptCode1
end-string.

INVOKE scriptControl1 "Reset".
INVOKE scriptControl1 "AddCode" USING scriptCode1.
INVOKE scriptControl1 "ExecuteStatement" USING "MYProgram".





Otra forma es buscando la ventana del appxxx.exe con api de windows : GetTopWindow , GetWindow , GetWindowTextA

special-names.
symbolic constant
gw_hwndfirst is 0
gw_hwndnext is 2
.
data division.
working-storage section.
01 get-this-window-handle.
05 this-window-handle pic s9(9) comp-5 value 0.
05 filler pic x(12) value spaces.

01 title-bar-search-string pic x(1025) value spaces.
01 title-bar-index pic 9(9) comp-5 value 0.

01 child-window-handle pic s9(9) comp-5 value 0.
01 parent-window-handle pic s9(9) comp-5 value 0.

01 length-of-title-bar-buffer pic s9(9) comp-5.
01 title-bar-buffer-max pic s9(9) comp-5.
01 title-bar-buffer pic x(1025) value spaces.

01 hwnd-type pic 9(9) comp-5.

01 null-value pic s9(9) comp-5 value 0.

linkage section.
01 title-bar-string pic x(1024).
01 found-window-sw pic 9(4) comp-5.
01 found-window-handle pic s9(9) comp-5.
01 return-value pic s9(9) comp-5.

procedure division using title-bar-string, found-window-sw, found-window-handle, return-value.
move 0 to return-value
move 0 to found-window-sw
move 0 to found-window-handle

compute title-bar-buffer-max = function length(title-bar-buffer)
*
* Let's make sure they passed the title bar string
*
if title-bar-string not > " "
move 1 to return-value
exit program
end-if
*
* Let's get the handle of this window
*
call "GetTopWindow" with STDCALL using
by value null-value
returning this-window-handle
*
* Now, let's find the length of the search string
*
move title-bar-string to title-bar-search-string
perform varying title-bar-index from 1025 by -1
until title-bar-search-string(title-bar-index:1) not = " "
continue
end-perform
*
* Now, let's get the first window
*
move gw_hwndfirst to hwnd-type
call "GetWindow" with STDCALL using
by value this-window-handle
by value hwnd-type
returning child-window-handle
if child-window-handle = 0
move 3 to return-value
exit program
end-if

move gw_hwndnext to hwnd-type
*
* Now, let's see if this is the target window, if not, loop through all open windows
*
perform until child-window-handle = 0
*
* Let's get the title bar text of this window
*
call "GetWindowTextA" with STDCALL using
by value child-window-handle
by reference title-bar-buffer
by value title-bar-buffer-max
returning length-of-title-bar-buffer *> Note, the length returned does NOT include the NULL byte
*
* If the window has a title bar, is it the one we're looking for?
*
if length-of-title-bar-buffer > 0
if title-bar-search-string(1:title-bar-index) = title-bar-buffer(1:title-bar-index)
move 1 to found-window-sw
move child-window-handle to found-window-handle
move 0 to return-value
exit program
end-if
end-if
*
* Get the next window
*
move child-window-handle to this-window-handle

call "GetWindow" with STDCALL using
by value this-window-handle
by value hwnd-type
returning child-window-handle

end-perform
*
* Didn't find the window
*
move 0 to return-value
move 0 to found-window-sw
move 0 to found-window-handle
exit program



Saludos ...

Kuk
5 de noviembre de 2024, 22:46
@Joseg,


ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 DWORD typedef pic s9(9) comp-5.
01 ULONG_PTR typedef pic 9(9) comp-5.
01 LONG typedef pic s9(9) comp-5.
01 HANDLE typedef pic s9(9) comp-5.

*>---------------------------------------------
01 TH32CS_SNAPPROCESS type DWORD value h"02".
*>---------------------------------------------

01 PROCESSENTRY32.
05 dwSize type DWORD.
05 cntUsage type DWORD.
05 th32ProcessID type DWORD.
05 th32DefaultHeapID pointer.
05 th32ModuleID type DWORD.
05 cntThreads type DWORD.
05 th32ParentProcessID type DWORD.
05 pcPriClassBase type LONG.
05 dwFlags type DWORD.
05 szExeFile pic x(1000).

01 snapshot type HANDLE.

01 returnCode type DWORD.

PROCEDURE DIVISION.

call "CreateToolhelp32Snapshot" with stdcall using by value TH32CS_SNAPPROCESS
by value 0
returning snapshot

move length of PROCESSENTRY32 to dwSize

call "Process32First" with stdcall using by value snapshot
by reference PROCESSENTRY32
returning returnCode

if returnCode = 0
call "GetLastError" with stdcall returning returnCode

display "GetLastError: ", returnCode

exit program
end-if

perform until returnCode = 0
if szExeFile(1:8) = "Main.exe" *> resto a nulos
INVOKE pow-self "DisplayMessage" USING "Bingo!" 64
end-if

INVOKE CmList1 "AddString" USING szExeFile

call "Process32Next" with stdcall using by value snapshot
by reference PROCESSENTRY32
returning returnCode
end-perform

Joseg
7 de noviembre de 2024, 11:01
Muchas gracias a todos por vuestra ayuda. :amigo:

Eu pretendia fazer isto: https://www.tek-tips.com/threads/set-exe-on-foreground-using-pid.1820890/
Apenas consegui fazer em "C" e Windev. Em anexo o código em "C".

Pero la idea era la siguiente: Con el número PID y no el título de la ventana (el título es dinámico), maximizar un programa de terceros y hacerse visible.


#include <windows.h>
#include <tlhelp32.h>
#include <iostream>
#include <cstdlib>

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
DWORD processId;
GetWindowThreadProcessId(hwnd, &processId);

// Verificar se o PID corresponde e se a janela é visível
if (processId == static_cast<DWORD>(lParam) && IsWindowVisible(hwnd)) {
// Maximizar e trazer a janela para o primeiro plano
ShowWindow(hwnd, SW_MAXIMIZE);
SetForegroundWindow(hwnd);
return FALSE; // Parar a enumeração
}

return TRUE; // Continuar a enumeração
}

void MaximizeMainApplicationWindow(DWORD pid) {
EnumWindows(EnumWindowsProc, static_cast<LPARAM>(pid));
}

int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <PID>" << std::endl;
return 1;
}

DWORD pid = std::atoi(argv[1]);
MaximizeMainApplicationWindow(pid);

return 0;
}

Kuk
7 de noviembre de 2024, 12:33
@Joseg, desde que descubrí cómo hacer funcionar el CALL BY VALUE en PowerCOBOL (https://www.cobolforo.es/showthread.php?1716-Arrastrar-y-soltar-archivos-(Drag-and-Drop)&p=9248&viewfull=1#post9248), absolutamente todo lo que se puede hacer en C, también se puede hacer en PowerCOBOL!

Así que, este código C también se puede convertir en PowerCOBOL! ;)

Joseg
7 de noviembre de 2024, 18:00
@Joseg, desde que descubrí cómo hacer funcionar el CALL BY VALUE en PowerCOBOL (https://www.cobolforo.es/showthread.php?1716-Arrastrar-y-soltar-archivos-(Drag-and-Drop)&p=9248&viewfull=1#post9248), absolutamente todo lo que se puede hacer en C, también se puede hacer en PowerCOBOL!

Así que, este código C también se puede convertir en PowerCOBOL! ;)

Admito que todo es posible ...pero no pude hacerlo, tampoco tengo mucha experiencia en llamadas a la API de WINDOWS.
Por ejemplo, esta función "&& IsWindowVisible(hwnd))" no devolvió el resultado correcto. Debo estar haciendo algo mal.


CALL 'IsWindowVisible' USING BY VALUE HWND
IF RETURN-CODE = 1
CALL 'ShowWindow' USING BY REFERENCE HWND,
BY VALUE 3 *> SW_MAXIMIZE
CALL 'SetForegroundWindow' USING BY REFERENCE HWND
IF RETURN-CODE = 1
DISPLAY "Janela trazida para frente com sucesso."
ELSE
DISPLAY "Falha ao trazer a janela para frente."
END-IF
ELSE
DISPLAY "Janela não está visível."
END-IF

José

Kuk
7 de noviembre de 2024, 21:58
@Joseg, acabo de probarlo y funciona:

Lo primero, creas un fichero nuevo en el directrio del proyecto y lo llamas EnumWindowsProc. Luego lo añades en el proyecto (import) y le pegas el siguiente contenido:


IDENTIFICATION DIVISION.
PROGRAM-ID. "EnumWindowsProc".
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 SW_MAXIMIZE PIC S9(9) COMP-5 VALUE 3.

01 P1 POINTER.
01 HWND REDEFINES P1 PIC S9(9) COMP-5.
01 P2 POINTER.
01 LPARAM REDEFINES P2 PIC S9(9) COMP-5.

01 processId PIC S9(9) COMP-5.
01 isVisble PIC S9(9) COMP-5.

LINKAGE SECTION.
77 PARM1 PIC S9(9) COMP-5.
77 PARM2 PIC 9(9) COMP-5.

01 RETURN-VALUE PIC 9(9) COMP-5.

PROCEDURE DIVISION WITH STDCALL USING PARM1, PARM2 RETURNING RETURN-VALUE.

MOVE FUNCTION ADDR(PARM1) TO P1
MOVE FUNCTION ADDR(PARM2) TO P2

CALL "GetWindowThreadProcessId" WITH STDCALL USING BY VALUE HWND
BY REFERENCE processId

CALL "IsWindowVisible" WITH STDCALL USING BY VALUE HWND RETURNING isVisble

IF processId = LPARAM AND
isVisble NOT = 0
CALL "ShowWindow" WITH STDCALL USING BY VALUE HWND, SW_MAXIMIZE
CALL "SetForegroundWindow" WITH STDCALL USING BY VALUE HWND

MOVE 0 TO RETURN-VALUE

ELSE
MOVE 1 TO RETURN-VALUE
END-IF

GOBACK
.



No olvides de añadirle la directiva ALPHAL(WORD) en las propiedades.

Luego desde donde quieras haces algo así (yo lo hago en el evento Click de un botón, recogiendo un PID desde CmText):


ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 ptr-EnumWindowsProc procedure-pointer.
01 num-ptr redefines ptr-EnumWindowsProc pic s9(9) comp-5.

01 pid pic s9(9) comp-5.
PROCEDURE DIVISION.

move pow-numeric of CmText1 to pid

set ptr-EnumWindowsProc to entry "EnumWindowsProc@8"

call "EnumWindows" with stdcall using by value num-ptr
by value pid


Ya nos cuentas qué tal ;)

Joseg
8 de noviembre de 2024, 10:46
Perfecto :amigo:. Kuk entiendes mucho de esto !!
Gracias.

José

Kuk
8 de noviembre de 2024, 17:58
@Joseg, de nada, para eso estamos :beber:

El problema era que oficialmente Fujitsu COBOL no trabaja con BY VALUE, pero de esta manera "hackeamos" el compilador quitándole este handicap y hacemos funcionar los CALL BY VALUE. Y con esta solución podemos reescribir el Windows por completo si queremos :rofl:

Kuk
10 de noviembre de 2024, 16:57
@Joseg, he encontrado otra manera de hacerlo funcionar sin pasar por PROCEDURE-POINTER, lo cual me hace suponer que funcionaría incluso en PowerCOBOL v3 (que no tiene PROCEDURE-POINTER):


ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 pid pic s9(9) comp-5.
01 hModule pic s9(9) comp-5.
01 pAddress pic s9(9) comp-5.

PROCEDURE DIVISION.

move pow-numeric of CmText1 to pid

call "GetModuleHandleA" with stdcall using by value h"00" returning hModule

call "GetProcAddress" with stdcall using by value hModule
by content "_EnumWindowsProc@8" & x"00"
returning pAddress

call "EnumWindows" with stdcall using by value pAddress
by value pid


Funciona perfectamente, lo que pasa es que aquí uso WinAPI para obtener la dirección de la función.

A ver si un día lo pruebo en PowerCOBOL v3, debería funcionar, salvo que haya algún imprevisto.

Joseg
11 de noviembre de 2024, 10:30
Buenos días Kuk :)

Se compila sin errores, pero el programa no se ejecuta.
Dando el mensaje:
EXCEPTION_ACCESS_VIOLATION(C0000005)

¿El programa "EnumWindowsProc" no tiene cambios?

Gracias,
José

Kuk
11 de noviembre de 2024, 10:47
@Joseg, a lo mejor no le has pasado ningún Nº de PID, porque a mi me funciona sin fallos.

También haz "Rebuild ALL" por si acaso. Aveces falla si no recompilamos por completo el proyecto (para refrescar todos los cachés, el Build es incremental).

No, en "EnumWindowsProc" no he hecho ningún cambio.

Joseg
11 de noviembre de 2024, 11:59
@Joseg, a lo mejor no le has pasado ningún Nº de PID, porque a mi me funciona sin fallos.

También haz "Rebuild ALL" por si acaso. Aveces falla si no recompilamos por completo el proyecto (para refrescar todos los cachés, el Build es incremental).

No, en "EnumWindowsProc" no he hecho ningún cambio.

Fiz "RebuildAll"
Powercobol 9.0


call "GetProcAddress" with stdcall using by value hModule
by content "EnumWindowsProc@8" & X"00"
returning pAddress


---> returning pAddress ---> pAddress = 0

Gracias

Kuk
11 de noviembre de 2024, 12:46
@Joseg, es que el nombre que le pones no es correcto. Desde fuera se le añade un guion bajo, por eso en vez de EnumWindowsProc@8 debe ser _EnumWindowsProc@8, por eso no te funciona. Copia y pega el código que puse yo tal cual y verás que funciona. ;)

fastpho
11 de noviembre de 2024, 13:19
Hola @Kuk , esto es buenisimo por que desde powercobol 5.0
no puedo usar procedure-pointer , habia intentado de
muchas formas poder llamar a una funcion y realizar un
callback , con este procediemiento ahora puedo
muchas gracias.

Probe el ejemplo de llamar a un .exe por Procees_id y me funciono
perfecto.

Saludos ...

Joseg
11 de noviembre de 2024, 13:30
@Joseg, es que el nombre que le pones no es correcto. Desde fuera se le añade un guion bajo, por eso en vez de EnumWindowsProc@8 debe ser _EnumWindowsProc@8, por eso no te funciona. Copia y pega el código que puse yo tal cual y verás que funciona. ;)

Primero probé _EnumWindowsProc@8, pero igualmente sin éxito.
Estoy haciendo esta llamada desde una DLL, ¿solo funciona si la llamo desde un EXE?

Gracias

fastpho
11 de noviembre de 2024, 13:41
Hola @Joseg , probe desde una dll y me funciono :mola::mola:
Saludos

Kuk
11 de noviembre de 2024, 13:44
@Joseg, has probado copiando mi código tal cual? A lo mejor hay algún pequeño error en alguna parte. Es muy raro que no te funcione, no tiene "explicación científica" y nos funciona a 2 personas... :piensa:
Si funciona en un EXE, en una DLL debe funcionar con más razón porque las DLLs son pensadas para compartir funciones, los EXE son los puntos de entrada (que lo pueden hacer también pero es más raro). En este caso con el EXE egenrado por PowerCOBOL va sujeto al Run-Time, tiene siempre expuesto el punto de entrada MAINFORM. Y si hay funciones añadidas por nosotros, también aparecen:

1007

@fastpho, no sabía que PowerCOBOL v5 no tenía tampoco PROCEDURE-POINTER. Me alegro de que te sirva el invento :bien:

Joseg
11 de noviembre de 2024, 16:51
@Joseg, has probado copiando mi código tal cual? A lo mejor hay algún pequeño error en alguna parte. Es muy raro que no te funcione, no tiene "explicación científica" y nos funciona a 2 personas... :piensa:
Si funciona en un EXE, en una DLL debe funcionar con más razón porque las DLLs son pensadas para compartir funciones, los EXE son los puntos de entrada (que lo pueden hacer también pero es más raro). En este caso con el EXE egenrado por PowerCOBOL va sujeto al Run-Time, tiene siempre expuesto el punto de entrada MAINFORM. Y si hay funciones añadidas por nosotros, también aparecen:

1007

@fastpho, no sabía que PowerCOBOL v5 no tenía tampoco PROCEDURE-POINTER. Me alegro de que te sirva el invento :bien:


Ok, usaré la primera forma. Llamarlo vía EXE funciona, vía DLL no funciona en absoluto.

Kuk
11 de noviembre de 2024, 21:05
@Joseg, mea culpa, es que hay un detalle importante! Efectivamente, no puede funcionar TAL CUAL en una DLL porque GetModuleHandleA, si no le damos nombre del módulo sino que le pasamos un NULO, devuelve el hModule del EXE que se cargó inicialmente (el Main, vamos). Así que luego GetProcAddress, aunque lo llamamos en una DLL, le pasamos el hModule que obtuvimos del EXE, y evidentemente no encuentra "EnumWindowsProc", (a no ser que también esté presente en el EXE).

Por lo tanto, si lo queremos hacer SOLO en una DLL, lo que hay que hacer es pasarle a GetModuleHandleA el nombre de la DLL en parámetro en vez de un NULO. Es decir, reemplazar:

call "GetModuleHandleA" with stdcall using by value h"00" returning hModule


por

call "GetModuleHandleA" with stdcall using by content "RgestAPI.dll" returning hModule


O si no, dejar el fichero "EnumWindowsProc" en el EXE y no meterlo en la DLL. De hecho es por eso que a @fastpho le ha funcionado, seguro que ha dejado el fichero "EnumWindowsProc" en el EXE pero hizo la llamada a GetProcAddress en la DLL pasándole el hModule del EXE que obtuvo llamando a GetModuleHandleA con el parámetro a NULO (h"00").

No sé si me he explicado bien.

fastpho
11 de noviembre de 2024, 21:35
@Kuk , en el .EXE deje "EnumWindowsProc" y en la .DLL
solamente me ti y funciono

move pow-numeric of CmText1 to pid.


call "GetModuleHandleA" with stdcall using by value 0 returning hModule

call "GetProcAddress" with stdcall using by value hModule
by content "_EnumWindowsProc@8" & X"00"
returning pAddress
display "pAddress: " , pAddress.

call "EnumWindows" with stdcall using by value pAddress
by value pid

Pero viendo el error de @Joseg le inserte el "EnumWindowsProc" a la .DLL y seguia funcionando
Luego quite del .EXE y el EnumWindows y lo deje en la .DLL y efectivamente no funciono
Espero a ver sido claro
Saludos1009

fastpho
11 de noviembre de 2024, 23:25
@Kuk, efectivamente para usar una .DLL , y colocar el EnumWindowsProc en ella , se debe llamar pasandole un valor por contenido

MOVE "SFAC03.DLL" & x"00" TO String-DLL.

* call "GetModuleHandleA" with stdcall using by value 0 returning hModule
call "GetModuleHandleA" with stdcall using by CONTENT String-DLL returning hModule
DISPLAY "hModule: " , hModule.

Funciona correctamente
Gracias
Saludos ...

Joseg
12 de noviembre de 2024, 12:31
@Joseg, mea culpa, es que hay un detalle importante! Efectivamente, no puede funcionar TAL CUAL en una DLL porque GetModuleHandleA, si no le damos nombre del módulo sino que le pasamos un NULO, devuelve el hModule del EXE que se cargó inicialmente (el Main, vamos). Así que luego GetProcAddress, aunque lo llamamos en una DLL, le pasamos el hModule que obtuvimos del EXE, y evidentemente no encuentra "EnumWindowsProc", (a no ser que también esté presente en el EXE).

Por lo tanto, si lo queremos hacer SOLO en una DLL, lo que hay que hacer es pasarle a GetModuleHandleA el nombre de la DLL en parámetro en vez de un NULO. Es decir, reemplazar:

call "GetModuleHandleA" with stdcall using by value h"00" returning hModule


por

call "GetModuleHandleA" with stdcall using by content "RgestAPI.dll" returning hModule


O si no, dejar el fichero "EnumWindowsProc" en el EXE y no meterlo en la DLL. De hecho es por eso que a @fastpho le ha funcionado, seguro que ha dejado el fichero "EnumWindowsProc" en el EXE pero hizo la llamada a GetProcAddress en la DLL pasándole el hModule del EXE que obtuvo llamando a GetModuleHandleA con el parámetro a NULO (h"00").

No sé si me he explicado bien.

Ahora si!!! Dominas completamente este tema!!!
También estudiaré un poco sobre el tema. El uso de la API de Windows puede ayudar en muchos escenarios.

Gracias

Kuk
12 de noviembre de 2024, 14:54
@Joseg, no es que me lo sepa todo de memoria, ni falta que hace. Como decía, el problema era que el compilador de Fujitsu no funciona BY VLUE. Pero engañándolo como lo hacemos, sí que funciona. Y en tal caso podemos hacer cualquier cosa, todo lo que se hace en C se puede hacer en PowerCOBOL. El resto es ver la documentación ;)