Iniciar Sesión

Ver la Versión Completa : [PowerCOBOL + WinAPI] Subclassing: recibir parámetros BY VALUE


Kuk
5 de enero de 2023, 19:06
Sabemos que existen varios modos de pasar parámetros en COBOL:

BY VALUE - pasa el valor
BY REFERENCE - pasa la dirección del campo para que el llamado pueda modificar datos en él
BY CONTENT - similar al anterior pero que es una copia de la variable, así el llamado no puede modificar nada en la variable de origen


Ahora, en C (y lógicamente en WinAPI, escrito en C), hay funciones que reciben parámetros BY VALUE. Por ejemplo una de las funciones más famosas que es WNDPROC:


LRESULT CALLBACK MainWndProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam) // second message parameter
{

switch (uMsg)
{
case WM_CREATE:
// Initialize the window.
return 0;

case WM_PAINT:
// Paint the window's client area.
return 0;

case WM_SIZE:
// Set the size and position of the window.
return 0;

case WM_DESTROY:
// Clean up window-specific data objects.
return 0;

//
// Process other messages.
//

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}


Estos parámetros entran por valor, o sea BY VALUE. Quiere decir que el que llame a esta función, lo que pase como parámetros, en ésta función se recibe tal cual (el valor) y no la dirección en memoria del mismo.
Lo que pasa es que el compilador de Fujitsu dice oficialmente que NO TRABAJA con parámetros BY VALUE en entrada. Esto limita a que no podamos definir funciones que reciban valores BY VALUE en la LINKAGE SECTION, lo cual significa que no podemos hacer subclassing, es decir sobrecargar funciones existentes de WinAPI porque no somos capaces de recibir los parámetros como lo hace C.

Pero lo desmiento totalmente. Hoy he conseguido hacerlo. Y esto quiere decir que podría reescribir toda la WinAPI en Cobol de Fujitsu sin limitación alguna.

Estaba echando un ojo al tema de @Josber: [Información] ToolTipText multilinea (https://www.cobolforo.es/showthread.php?1580-ToolTipText-multilinea)
He mirado ejemplos para hacerlo, dicen de utilizar la función WinAPI siguiente: EnumWindows function (winuser.h) - Win32 apps | Microsoft Learn (https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumwindows)
Esta función necesita pasar como parámetro otra función definida por nosotros, a la que le va a pasar el HWND de toda ventana que encuentre, y lo hará BY VALUE, cosa que el compilador de Fujitsu no soporta (de forma nativa).

Pero le he engañado y lo he hecho funcionar de la siguiente manera:

Creamos un fichero CallBackFunc.cbl (en el directorio, por fuera, en el explorador de Windows) y lo insertamos en el proyecto de PowerCOBOL. En propiedades añadimos la directiva ALPHAL(WORD). El contenido del fichero creado es el siguiente:

IDENTIFICATION DIVISION.
PROGRAM-ID. "CallBackFunc".
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 p1 pointer.
01 w-hwnd redefines p1 pic s9(9) comp-5.
01 p2 pointer.
01 w-lParam redefines p2 pic s9(9) comp-5.

LINKAGE SECTION.
01 hwnd pic s9(9) comp-5.
01 lParam pic s9(9) comp-5.
PROCEDURE DIVISION WITH STDCALL LINKAGE using hwnd lParam.

move function addr(hwnd) to p1
move function addr(lParam) to p2

display "hwnd : " w-hwnd
display "lParam: " w-lParam

goback
.


Luego en cualquier lado, en mi ejemplo en el evento Click de un botón, le metemos este código:

ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 p-hwnd PIC S9(9) COMP-5.
01 c-hwnd PIC S9(9) COMP-5.
01 rc PIC S9(9) COMP-5.

01 PTR-callBackFnc procedure-pointer.
01 cbf redefines PTR-callBackFnc PIC S9(9) COMP-5.

PROCEDURE DIVISION.

set PTR-callBackFnc to entry "CallBackFunc@8"

move "hwnd" of pow-self to c-hwnd

call "GetParent" with stdcall using by value c-hwnd returning p-hwnd

display "M -> c-hwnd: " c-hwnd " p-hwnd: " p-hwnd

call "EnumWindows" with stdcall using by value cbf
by value 26
returning rc

display "M -> EnumChildWindows rc: " rc



¡Y listo! Tenemos funcionalidad nativa de C/WinAPI con el compilador de Fujitsu!!!

Al ejecutar el programa, se ve el valor 26 que le paso en el evento del botón, lo hago BY VALUE y es correctamente recuperado!