PDA

Ver la Versión Completa : [Sintaxis] CALLBACK WindowProc


Kuk
11 de marzo de 2015, 10:32
Hola a todos. Ya puse un post sobre este asunto en el otro foro, pero no he logrado desde entonces arreglar el tema.

Estoy intentando crear una funcion COBOL para imitar/sustituit o lo que es lo mismo hacer subclassing de CallWindoProc. Para ello hay que simular algo asi:

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CREATE:
Button1 = CreateWindow("Button", "Child", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
10, 80, 80, 40, hwnd, (HMENU)ID_BUTTON,
hInstance, NULL);
break;
case WM_COMMAND:
if(LOWORD(wParam)==ID_BUTTON)
{
CreateChildWindow(); // В этой функции создается дочернее окно
}
break;

case WM_NCACTIVATE:
wParam = isActive;
return DefWindowProc (hwnd, message, wParam, lParam);

case WM_DESTROY:
PostQuitMessage (0);
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}

Lo hago de la siguiente manera:


*****************************************
WORKING-STORAGE SECTION.
LINKAGE SECTION.
01 LNK-HWND BINARY-LONG.
01 LNK-MSG PIC 9(9) COMP-5.
01 LNK-WPARAM BINARY-LONG.
01 LNK-LPARAM BINARY-LONG.

01 LNK-RESULT BINARY-LONG.

PROCEDURE DIVISION WITH STDCALL LINKAGE
USING LNK-HWND LNK-MSG LNK-WPARAM LNK-LPARAM
RETURNING LNK-RESULT.

CALL "CallWindowProcA" WITH STDCALL ...



Pero no recibe los parametros bien y no logro entender por que. A veces recibe los recibe, pero solo 1 campo por cada llamada y no los 4 a la vez, y encima lo hace casi siempre en el primer campo, otras veces no recibe nada...

En teoria llamamos al WinAPI con STDCALL y va bien, o sea que en teoria deberia funcionar bien con WITh stdcall en PROCEDURE pero no se por que no funciona...
A lo mejor alguna opcion de compilacion? He mirado el manual pero no he visto nada que pueda cambiar algo en esto.

Rapinto
11 de marzo de 2015, 23:13
Kuk,

Não entendo muito bem o que pretendes fazer e qual é o erro.
Desculpa lá, o meu espanhol é muito fraco e não consigo entender muito bem.

No entanto, pelo que vejo, tens uma Procedure Division "with STDCALL" - eu nunca utilizei isso.

Nas chamadas a WINAPI aí sim utilizei em muitos casos :


CALL "GetForegroundWindow" WITH STDCALL LINKAGE
RETURNING WS-HANDLE.
*
CALL "GetWindowLongA" WITH STDCALL USING BY VALUE WS-HANDLE
BY VALUE STYLE
RETURNING ATTRIBUTE.
IF ATTRIBUTE = ZERO GO TO MAIN-99.
*

CALL "GetTempPathA" WITH STDCALL LINKAGE USING
BY VALUE WSWINTMPDIRLEN
BY REFERENCE WSWINTMPDIR.
*
CALL "GetTempFileNameA" WITH STDCALL LINKAGE USING
BY REFERENCE WSWINTMPDIR
BY REFERENCE WSPREFIX
BY VALUE WSUNIQUE
BY REFERENCE WSTMPFILENAME
RETURNING RESULT.


Tenta explicar-me melhor, pode ser que eu consiga ajudar,
Reparei que podes ter problemas com o tipo de USING : pode ser por 2 processos: By Reference or By Value.
Isto pode fazer muita diferença.

Un Saludo,
Rui Pinto

Kuk
12 de marzo de 2015, 09:42
Rapinto, en princpio lo que intento es simular MDI Form en PowerCOBOL.
En realidad, cada Form en PowerCOBOL se compone de:

Una WindowForm que es la que contiene SystemMenu, Border etc.
Un Frame (Frame de C++, loadable. No hablo de CmFrame), que es en el que realmente ponemos los controles.


Pero a nivel del compilador en modo Diseño, nosotros pensamos que es un Form. Si en en un Form haces GetParent, obtienes el hwnd del ParentForm.

Lo que yo hago para simular MDI, es ChildForm.SetParent = ParentForm.hwnd y asi el ParentForm se hace Container del ChildForm. El problema es que cuando haces click en ChildForm, el ParentForm pierde focus, y vice versa.

Hablé con gente de C++/Delphi + WinAPI. Me dijeron que en este caso hay que hacer subclassing de la ventana. Es decir:


Definir propia procedure equivalente a CallWindowProc y posicionar un PROCEDURE-POINTER MyWndProc.
Obtener PROCEDURE-POINTER de CallWindowProc actual, el que actualmente es llamado por el Window:
En el evendo Window.Opened



******** MyWndProc. Va a ser llamado por Windows, por eso tiene STDCALL
IDENTIFICATION DIVISION.
PROGRAM-ID. MyWndProc.

WORKING-STORAGE SECTION.
01 PTR-OldWndProc IS EXTERNAL PIC S9(9) COMP-5.

LINKAGE SECTION.
01 LNK-RESULT PIC S9(9) COMP-5.

01 LNK-HWND PIC S9(9) COMP-5.
01 LNK-MSG PIC S9(9) COMP-5.
01 LNK-WPARAM PIC 9(9) COMP-5.
01 LNK-LPARAM PIC S9(9) COMP-5.

PROCEDURE DIVISION WITH STDCALL USING LNK-HWND LNK-MSG LNK-WPARAM LNK-LPARAM RETURNING LNK-RESULT.

IF LNK-MSG = <<LOST FOCUS MESSAGE>> NO ME ACURDO EXACTAMENTE
MOVE 0 TO LNK-MSG
END-IF

CALL "CallWindowProc" WITH STDCALL USING BY VALUE PTR-OldWndProc
BY VALUE LNK-HWND
BY VALUE LNK-MSG
BY VALUE LNK-WPARAM
BY VALUE LNK-LPARAM
RETURNING LNK-RESULT.

EXIT PROGRAM.
END PROGRAM MyWndProc.



******** MainForm.Opened
WORKING-STORAGE SECTION.
01 WS-HWND PIC S9(9) COMP-5.
01 ParentHWND PIC S9(9) COMP-5.
01 PTR-OldWndProc IS EXTERNAL PIC S9(9) COMP-5.
01 PPTR REDEFINES PTR-OldWndProc PROCEDURE-POINTER.
01 PTR-MyWndProc PROCEDURE-POINTER.

PROCEDURE DIVISION.

MOVE "hwnd" OF POW-SELF TO WS-HWND

CALL "GetParent" WITH STDCALL USING BY VALUE LNK-HWND
RETURNING ParentHWND.

CALL "GetWindowLong" WITH STDCALL USING BY VALUE ParentHWND
BY VALUE GWL_WNDPROC
RETURNING PPTR.

SET PTR-MyWndProc TO ENTRY "MyWndProc"

CALL "SetWindowLong" WITH STDCALL USING BY VALUE ParentHWND
BY VALUE GWL_WNDPROC
BY VALUE PTR-MyWndProc
RETURNING PPTR.


Rui, el codigo no es exacto, lo acabo de escribir de memoria (estoy en el trabajo). Pero entenderas lo que hago. Es sustiuir CallWindoProc por MyWndProc, camptar WindowMessage, si es desactivar Focus visual, muevo 0, y llamo default CallWindoProc con PTR-OldWndProc.

A ver que opians.

Rapinto
12 de marzo de 2015, 23:53
Kuk,

Estive a analisar melhor e encontrei este texto:

AllAPI.net - Your #1 source for using API-functions in Visual Basic! (http://allapi.mentalis.org/vbtutor/subclass.shtml)

que explica Subclassing muito bem. (Tem exemplo a funcionar bem com a source em VB6).
Segundo este texto, o que estás a fazer parece-me numa primeira analise correto.

Mas vou continuar a ver melhor.
Se descobrires mais alguma coisa diz-me.
Saludos,
Rui

Kuk
13 de marzo de 2015, 09:17
Rapinto, ando un poco mal de tiempo, pero lo que he pensafo de probar es en modo OO COBOL. Es decir, crear aplicacion con la opcion 2. Ahi a lo mejor funciona...

Lo que no entiendo es que si llamamos API-s con STDCALL bien, significa que la CALL-CONVENTION es correcta para WinAPI. Pero (!!!), al ser llamada MyWndProc, recibe parametros pero no todos, y en campos diferentes. Lo que he podido detectar ha sido que a veces (no siempre), es como si por cada campo hay 1 llamada. Es decir:


Call MyWndProc USING hWnd
Call MyWndProc USING Message
Call MyWndProc USING wParam
Call MyWndProc USING lParam


En lugar de llamarse 1 vez con los 4:


Call MyWndProc USING hWnd, Message, wParam, lParam


Lo que a mi me dice que:


Sea la CALL-CONVENTION no es realmente la adecuada (pero es menos probable)
Sea que CALLBACK no funciona en procedres COBOL, al menos en modo "1 - COBOL85". Por eso quiero probar con modo "2 - OO COBOL"


Añadido despues de 13 horas 38 minutos
Rui, he encontrado esto en el NetCOBWinUsersGuide.pdf:


NOTES:
When calling COBOL programs from COBOL programs, you cannot pass parameters
with “USING BY VALUE.”


El problema no es CALL-CONVENTION. El problema es BY VALUE. En cualquier WITH, sea C, STDCALL o COBOL (sin nada), si pasas valor BY VALUE - el programa se cierra con error...

Kuk
27 de marzo de 2015, 20:37
Al final he hecho una DLL en C++ a la cual paso el OldWndProc y en la cual he definido MyWndProc.

Funciona 100%! Asi que he podido simular MDI MainForm en PowerCOBOL! :mola:

Eslopes
25 de agosto de 2015, 08:48
Olá,

fiquei curioso para ver como fica uma aplicação Powercobol MDI. Poderia compartilhar um screenshot?

Saludos, Emerson

Kuk
25 de agosto de 2015, 19:34
eslopes, aquí lo tienes ;)

Pero ojo, no es MDI realmente, es sólo una simulación. Lo que se hace es que la ventana "MDI" no pierda foco visualmente. Como verás en los marcos amarillos, visualmente los 2 ControlBox están activos.

Eslopes
26 de agosto de 2015, 01:34
Gracias pelo screenshot.

Entendo que seja uma simulação, pero me parece que a janela CfForm1 não pode ultrapassar os limites da janela principal, certo ?

Kuk
26 de agosto de 2015, 09:13
eslopes, claro, de eso se trata. La ventana principal se hace Parent de las ventanas Child. Si muevo la ventana Principal, se mueven todas las ventanas.

Josber
26 de agosto de 2015, 10:35
Perdona la ignorancia, pero ... ¿para que necesitas ésto realmente?, porque, por lo que entiendo, con esto puedes tener el foco en 2 form a la vez, creo, ¿no?

Un saludo.-

Kuk
26 de agosto de 2015, 17:57
Josber, no es eso. Una ventana MDI controla las ventanas "hijo". Entonces, una ventana MDI es como si fuese lo mismo que el escritorio para los programas de Windows.

La ventaja de esto, es que puedes tener una ventana principal a lo Escritorio de Windows, con varias ventanas dentro, las cuales puedes incluso "pestañear" y etc.

Muchos programas que usamos son MDI, el UltraEdit, no sé, los compiladores, por jemeplo NetExpress... Lo bueno de esto es poder cargar y cerrar ventanas en el mismo rango de pantalla, es cómodo para aplicaciones grandes. ;)