rochinha Posted September 9, 2014 Report Share Posted September 9, 2014 Amiguinhos, Aquele velho sonho de conseguir executar código xBase contido em uma .DLL compilada com Harbour se concretizou para mim. Noites sem dormir e muita pesquisa, testes, compilações, chingamentos e sem sapeca-iá-iá, mas consegui. Meus primeiros testes foram com exemplos existentes em todo lugar, Harbour, xHarbour, Fivewin, etc. Busquei informações de como o RunDLL32 do Windows trabalhava e fiz minhas tentativas. Num primeiro momento consegui fazer um EXE executar uma função em uma DLL mas só executava a primeira função que encontrava. Bom já era um começo, mas ao retornar ao EXE paulava. Tentei com RunDLL32 chamado do EXE e não enfrentava mais este problema, mas tinha uma demora de uns segundos e não era o que eu queria. Fiz meu próprio RunDLL32 mas ainda tinha de executá-lo indiretamente. Bom enfim, cheguei onde queria e o primeiro passo para isto foi compilando o código de minha DLL: rochadll.prg /* * Jose Carlos da Rocha * Trabalho com DLL de codigo xBase para uso com Harbour * Sao Paulo - 09/09/2014 * Baseados nos exemplos BabuDLL e outros */ #include "fivewin.ch" #pragma BEGINDUMP #include <windows.h> #include <hbvm.h> #include <hbapiitm.h> BOOL WINAPI DllEntryPoint( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) { HB_SYMBOL_UNUSED( hinstDLL ); HB_SYMBOL_UNUSED( fdwReason ); HB_SYMBOL_UNUSED( lpvReserved ); switch( fdwReason ) { case DLL_PROCESS_ATTACH: hb_vmInit( FALSE ); break; case DLL_PROCESS_DETACH: hb_vmQuit(); break; } return TRUE; } void pascal __export HBDLLENTRY( char * cProcName ) { hb_itemDoC( cProcName, 0, 0 ); return 0; } void pascal __export CusTstBrw() { hb_itemDoC( "CusTstBrw", 0 ); } void pascal __export HBDLLENTRY2( char * cProcName, PHB_ITEM pParam1, PHB_ITEM pParam2 ) { hb_itemDoC( cProcName, 2, pParam1, pParam2 ); } #pragma ENDDUMP /* * MENUITEM "&Clientes..." ACTION HbDllEntry( "Customer" ) MESSAGE "Manutencao de Clientes" * Esta funcao foi chamada atraves de parametro da funcao exportavel hbDLLEntry() * Chamada indireta, pois a funcao abaixo passa por outra funcao para agir * Aqui o exemplo CUSTOMER foi imputado na DLL para demonstrar que trechos grandes de codigo * podem residir dentro de uma DLL e serem chamados a partir de um EXE externo. */ #include "Customer.ch" function Customer() local oWnd, oBar local oClients, oClient //local oName, cName SET _3DLOOK ON USE Customer SHARED NEW ALIAS Clients USE Sales SHARED NEW SELECT Clients DEFINE WINDOW oWnd TITLE "Reporting tools" MDI ; MENU BuildMenu(oClients) COLOR "N/W" DEFINE BUTTONBAR oBar OF oWnd SIZE 60, 60 2007 DEFINE BUTTON OF oBar ACTION MsgInfo( "Click" ) ; FILENAME "..\bitmaps\attach.bmp" PROMPT "Attach" DEFINE BUTTON OF oBar ACTION MsgInfo( "Click" ) ; FILENAME "..\bitmaps\calendar.bmp" PROMPT "Calendar" DEFINE BUTTON OF oBar ACTION MsgInfo( "Click" ) ; FILENAME "..\bitmaps\people2.bmp" PROMPT "Clients" DEFINE BUTTON OF oBar ACTION MsgInfo( "Click" ) SET MESSAGE OF oWnd TO "Testing the FiveWin Report Class" CENTERED ACTIVATE WINDOW oWnd CLOSE DATABASES return nil function BuildMenu(oClients) local oMenu MENU oMenu MENUITEM "&DataBases" MENU MENUITEM "&Clients..." ACTION BrwClients(oClients) ; MESSAGE "Clients management" MENUITEM "&Report..." ACTION GenReport() SEPARATOR MENUITEM "&End" ACTION oWnd:End() ; MESSAGE "End this test" ENDMENU oMenu:AddMdi() // Add standard MDI menu options ENDMENU return oMenu function BrwClients(oClients) local oBrw, oIco, oBarBrw if oClients != nil return nil endif DEFINE ICON oIco FILENAME "..\icons\customer.ico" DEFINE WINDOW oClients TITLE "Clients management" ; MDICHILD ICON oIco DEFINE BUTTONBAR oBarBrw OF oClients DEFINE BUTTON OF oBarBrw ACTION ShowClient(oClients) @ 2, 0 LISTBOX oBrw FIELDS OF oClients ; SIZE 500, 500 // ON CHANGE ChangeClient(oClients) oClients:SetControl( oBrw ) ACTIVATE WINDOW oClients ; VALID( oClients := nil, .t. ) // We destroy the object return nil function GenReport() local oWnd, oIco DEFINE ICON oIco FILENAME "..\icons\print.ico" DEFINE WINDOW oWnd MDICHILD TITLE "Clients report" ; VSCROLL HSCROLL ICON oIco ACTIVATE WINDOW oWnd return nil function ShowClient(oClients) local oIco, oClient local oName, cName if oClient != nil return nil endif DEFINE ICON oIco FILENAME "..\icons\Person.ico" DEFINE DIALOG oClient RESOURCE "Client" ; ICON oIco TITLE "Detalhes" REDEFINE SAY ID 3 OF oClient // To get the proper color REDEFINE SAY ID 4 OF oClient REDEFINE SAY ID 5 OF oClient REDEFINE GET oName VAR cName ID ID_NAME OF oClient REDEFINE BUTTON ID ID_NEXT OF oClient ACTION GoNext(oClients,oName) SELECT Sales // We select Sales to properly initialize the Browse REDEFINE LISTBOX FIELDS ID ID_SALES OF oClient ACTIVATE DIALOG oClient CENTERED NOWAIT ; VALID ( oClient := nil, .t. ) // Destroy the object SELECT Clients return nil function ChangeClient(oClients,oName) if oClients != nil cName = AllTrim( Clients->Last ) + ", " + Clients->First oName:Refresh() endif return nil function GoNext(oClients,oName) if oClients != nil oClients:oControl:GoDown() else SKIP if EoF() GO BOTTOM endif endif ChangeClient(oClients,oName) return nil /* * MENUITEM "&Browse..." ACTION HbDllEntry( "CusTeste" ) MESSAGE "Browse de Clientes" * Esta funcao foi chamada atraves de parametro da funcao exportavel hbDLLEntry() * Chamada indireta, pois a funcao abaixo passa por outra funcao para agir */ function CusTeste() USE Customer SHARED NEW ALIAS Clients Browse() CLOSE DATABASES return .t. /* * MENUITEM "&Customer..." ACTION CusTstBrw() MESSAGE "Browse de Clientes" * Esta funcao foi chamada dentro da DLL usando o proprio nome ao inves de * usar hbDLLEntry(), desta forma ficou mais legal */ function CusTstBrw() USE Sales SHARED NEW Browse() CLOSE DATABASES return .t. Dentro do código da DLL existem aplicativos que serão chamados pela aplicação principal, Customer(), CusTeste() e CusTstBrw(). Atentem para o seguinte trecho: #pragma BEGINDUMP ... void pascal __export HBDLLENTRY( char * cProcName ) ... void pascal __export CusTstBrw() ... #pragma ENDDUMP Vejam que HBDLLENTRY e CusTstBrw são exportadas, ou seja, são visíveis as chamadas à DLL. Então como compilar este .PRG e transformá-lo em uma .DLL? Eu usei o bom-e-velho BUILDH.BAT com algumas alterações, vejam os trechos que foram modificados: %hdir%\bin\harbour %1 /n /i%fwh%\include;%hdir%\include /w0 /p %3 /d__HARBOUR__ > comp.log IF ERRORLEVEL 1 GOTO COMPILEERRORS @type comp.log echo -O2 -e%1.exe -I%hdir%\include;%bcdir%\include %1.c > b32.bc %bcdir%\bin\bcc32 -M -c @b32.bc copy %bcdir%\lib\uuid.lib :ENDCOMPILE IF EXIST %1.rc %bcdir%\bin\brc32 -r -I%bcdir%\include %1 rem IF EXIST %1.rc %vcdir%\bin\rc -r -d__FLAT__ %1 echo %bcdir%\lib\c0d32.obj + > b32.bc Quem usa este .BAT dirá, mas não tem nada de diferente neste trecho, mas tem sim e está na última linha, onde se vê echo %bcdir%\lib\c0d32.obj + > b32.bc Quando compilamos nossos programas para gerar executáveis o arquivo c0w32.obj é o usado, mas neste caso usaremos o c0d32.obj. Outra linha alterada no nosso BUILDH.BAT é a linha de chamada do iLink32.exe if %GT% == gtgui %bcdir%\bin\ilink32 -Gn -aa -s -Tpd @b32.bc No lugar de -Gn -aa -s -Tpe eu alterei para -Gn -aa -s -Tpd, onde e é para EXE e d é para DLL. Bom, depois de gerada a DLL é possivel testá-la sem precisar do uso do aplicativo principal, bastando usar para isto o RunDLL32.exe do Windows, executando um comando simples: %windir%\System32\RunDLL32 rochadll.dll,CusTstBrw Leve em consideração que os testes foram feitos dentro da pasta SAMPLES do Fivewin, portanto as tabelas CUSTOMER.DBF e SALES.DBF serao usadas. Se a DLL foi bem gerada um browse aparecerá mostrando os registros da tabela. Agora vamos a parte do aplicativo principal. Este poderá ser compilado normalmente usando o BUILDH.BAT: rocha.prg /* * Jose Carlos da Rocha * Trabalho com DLL de codigo xBase para uso com Harbour * Sao Paulo - 09/09/2014 * Baseados nos exemplos BabuDLL e outros */ #include "FiveWin.ch" FUNCTION Main() local oWndMain, oBarMain DEFINE WINDOW oWndMain TITLE "Janela dentro do EXE" MDI MENU BuildMenuMain() COLOR "N/W" DEFINE BUTTONBAR oBarMain OF oWndMain SIZE 60, 60 2007 DEFINE BUTTON OF oBarMain ACTION WinExec( "RunDLL32.exe rochadll.dll,CusTstBrw" ) DEFINE BUTTON OF oBarMain ACTION UseDLL( "CusTstBrw", "rochadll.dll" ) SET MESSAGE OF oWndMain TO "Testing the FiveWin DLLs" CENTERED ACTIVATE WINDOW oWndMain MAXIMIZED VALID MsgYesNo( "Quer sair?" ) RETURN nil FUNCTION BuildMenuMain() local oMenu MENU oMenu MENUITEM "Administracao" MENU MENUITEM "&Clientes..." ACTION HbDllEntry( "Customer" ) MESSAGE "Manutencao de Clientes" MENUITEM "&Browse..." ACTION HbDllEntry( "CusTeste" ) MESSAGE "Browse de Clientes" MENUITEM "&Customer..." ACTION CusTstBrw() MESSAGE "Browse de Clientes" SEPARATOR MENUITEM "&Sair" ACTION oWnd:End() ; MESSAGE "Sair do sistema" ENDMENU oMenu:AddMdi() // Add standard MDI menu options ENDMENU return oMenu FUNCTION UseDLL( cFuncName, cDllName ) local hDLL, cFarProc hDLL = LoadLibrary( cDllName ) if hDll > 32 cFarProc := GetProcAddress( hDLL, "DLLSYMINIT", .T., _INT ) CallDLL( cFarProc ) Eval( &( "{||" + cFuncName + "() }" ) ) endif return nil //-------------------------------------------------------------------------// #include "dll.ch" DLL32 FUNCTION CusTstBrw() AS LONG PASCAL LIB "rochadll.dll" DLL32 FUNCTION HBDLLENTRY( cProc AS LPSTR ) AS LONG PASCAL LIB "rochadll.dll" DLL32 FUNCTION HBDLLENTRY2( cProc AS LPSTR, pItem1 AS LONG, pItem2 AS LONG ) AS LONG PASCAL LIB "rochadll.dll" DLL32 FUNCTION HBDLLENTRY3( cProc AS LPSTR, pItem1 AS _INT, pItem2 AS _INT ) AS _INT PASCAL LIB "rochadll.dll" Vejamos agora algumas caracteristicas: ... DEFINE BUTTON OF oBarMain ACTION WinExec( "RunDLL32.exe rochadll.dll,CusTstBrw" ) ... No trecho acima faço execução de uma função dentro da .DLL usando execução de aplicativo externo. ... DEFINE BUTTON OF oBarMain ACTION UseDLL( "CusTstBrw", "rochadll.dll" ) ... Neste trecho, usando funções do Harbour exemplifico como chamar uma função existente na .DLL. Esta função deve ser EXPORTável e para tal foi necessária a definição de chamada desta função: ... DLL32 FUNCTION CusTstBrw() AS LONG PASCAL LIB "rochadll.dll" ... Abaixo vemos as formas de chamar nossas funções usando HbDllEntry, mas particularmente acho feio assim: ... MENUITEM "&Clientes..." ACTION HbDllEntry( "Customer" ) MESSAGE "Manutencao de Clientes" MENUITEM "&Browse..." ACTION HbDllEntry( "CusTeste" ) MESSAGE "Browse de Clientes" ... A função HbDllEntry() enxerga as funções que não são EXPORTáveis. Vale lembrar que as .DLL não ficaram pequenas, mas o fator levado em consideração é que para a manutenção fica mais produtivo ter várias .DLLs no sistema e ao modificar uma ou outra, podemos atualizar somente elas sem prejuízo ao EXE principal. Outra coisa importante: As telas usadas no aplicativo, não importando qual .DLL poderá usá-la, deverão ser compiladas com o .EXE principal. O Harbour usado foi a versão 3.2-17626. O download deste trabalho encontra-se no 4shared.com. Tenho grande certeza, que seria possivel chamar código xBase contido nas .DLLs através de outras linguagens como Delphi ou Visual Basic. Vale a pena testar e retornar. aferra 1 Quote Link to comment Share on other sites More sharing options...
gilmer Posted September 9, 2014 Report Share Posted September 9, 2014 Muito Bom! rochinha 1 Quote Link to comment Share on other sites More sharing options...
william Posted September 9, 2014 Report Share Posted September 9, 2014 Rochinha excelente !!! Vou testar , mas desde já muito grato pela contribuição ! Abraço William Adami rochinha 1 Quote Link to comment Share on other sites More sharing options...
crisvam Posted September 9, 2014 Report Share Posted September 9, 2014 Amiguinhos, Aquele velho sonho de conseguir executar código xBase contido em uma .DLL compilada com Harbour se concretizou para mim. Noites sem dormir e muita pesquisa, testes, compilações, chingamentos e sem sapeca-iá-iá, mas consegui. Meus primeiros testes foram com exemplos existentes em todo lugar, Harbour, xHarbour, Fivewin, etc. Busquei informações de como o RunDLL32 do Windows trabalhava e fiz minhas tentativas. Num primeiro momento consegui fazer um EXE executar uma função em uma DLL mas só executava a primeira função que encontrava. Bom já era um começo, mas ao retornar ao EXE paulava. Tentei com RunDLL32 chamado do EXE e não enfrentava mais este problema, mas tinha uma demora de uns segundos e não era o que eu queria. Fiz meu próprio RunDLL32 mas ainda tinha de executá-lo indiretamente. Bom enfim, cheguei onde queria e o primeiro passo para isto foi compilando o código de minha DLL: rochadll.prg /* * Jose Carlos da Rocha * Trabalho com DLL de codigo xBase para uso com Harbour * Sao Paulo - 09/09/2014 * Baseados nos exemplos BabuDLL e outros */ #include "fivewin.ch" #pragma BEGINDUMP #include <windows.h> #include <hbvm.h> #include <hbapiitm.h> BOOL WINAPI DllEntryPoint( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) { HB_SYMBOL_UNUSED( hinstDLL ); HB_SYMBOL_UNUSED( fdwReason ); HB_SYMBOL_UNUSED( lpvReserved ); switch( fdwReason ) { case DLL_PROCESS_ATTACH: hb_vmInit( FALSE ); break; case DLL_PROCESS_DETACH: hb_vmQuit(); break; } return TRUE; } void pascal __export HBDLLENTRY( char * cProcName ) { hb_itemDoC( cProcName, 0, 0 ); return 0; } void pascal __export CusTstBrw() { hb_itemDoC( "CusTstBrw", 0 ); } void pascal __export HBDLLENTRY2( char * cProcName, PHB_ITEM pParam1, PHB_ITEM pParam2 ) { hb_itemDoC( cProcName, 2, pParam1, pParam2 ); } #pragma ENDDUMP /* * MENUITEM "&Clientes..." ACTION HbDllEntry( "Customer" ) MESSAGE "Manutencao de Clientes" * Esta funcao foi chamada atraves de parametro da funcao exportavel hbDLLEntry() * Chamada indireta, pois a funcao abaixo passa por outra funcao para agir * Aqui o exemplo CUSTOMER foi imputado na DLL para demonstrar que trechos grandes de codigo * podem residir dentro de uma DLL e serem chamados a partir de um EXE externo. */ #include "Customer.ch" function Customer() local oWnd, oBar local oClients, oClient //local oName, cName SET _3DLOOK ON USE Customer SHARED NEW ALIAS Clients USE Sales SHARED NEW SELECT Clients DEFINE WINDOW oWnd TITLE "Reporting tools" MDI ; MENU BuildMenu(oClients) COLOR "N/W" DEFINE BUTTONBAR oBar OF oWnd SIZE 60, 60 2007 DEFINE BUTTON OF oBar ACTION MsgInfo( "Click" ) ; FILENAME "..\bitmaps\attach.bmp" PROMPT "Attach" DEFINE BUTTON OF oBar ACTION MsgInfo( "Click" ) ; FILENAME "..\bitmaps\calendar.bmp" PROMPT "Calendar" DEFINE BUTTON OF oBar ACTION MsgInfo( "Click" ) ; FILENAME "..\bitmaps\people2.bmp" PROMPT "Clients" DEFINE BUTTON OF oBar ACTION MsgInfo( "Click" ) SET MESSAGE OF oWnd TO "Testing the FiveWin Report Class" CENTERED ACTIVATE WINDOW oWnd CLOSE DATABASES return nil function BuildMenu(oClients) local oMenu MENU oMenu MENUITEM "&DataBases" MENU MENUITEM "&Clients..." ACTION BrwClients(oClients) ; MESSAGE "Clients management" MENUITEM "&Report..." ACTION GenReport() SEPARATOR MENUITEM "&End" ACTION oWnd:End() ; MESSAGE "End this test" ENDMENU oMenu:AddMdi() // Add standard MDI menu options ENDMENU return oMenu function BrwClients(oClients) local oBrw, oIco, oBarBrw if oClients != nil return nil endif DEFINE ICON oIco FILENAME "..\icons\customer.ico" DEFINE WINDOW oClients TITLE "Clients management" ; MDICHILD ICON oIco DEFINE BUTTONBAR oBarBrw OF oClients DEFINE BUTTON OF oBarBrw ACTION ShowClient(oClients) @ 2, 0 LISTBOX oBrw FIELDS OF oClients ; SIZE 500, 500 // ON CHANGE ChangeClient(oClients) oClients:SetControl( oBrw ) ACTIVATE WINDOW oClients ; VALID( oClients := nil, .t. ) // We destroy the object return nil function GenReport() local oWnd, oIco DEFINE ICON oIco FILENAME "..\icons\print.ico" DEFINE WINDOW oWnd MDICHILD TITLE "Clients report" ; VSCROLL HSCROLL ICON oIco ACTIVATE WINDOW oWnd return nil function ShowClient(oClients) local oIco, oClient local oName, cName if oClient != nil return nil endif DEFINE ICON oIco FILENAME "..\icons\Person.ico" DEFINE DIALOG oClient RESOURCE "Client" ; ICON oIco TITLE "Detalhes" REDEFINE SAY ID 3 OF oClient // To get the proper color REDEFINE SAY ID 4 OF oClient REDEFINE SAY ID 5 OF oClient REDEFINE GET oName VAR cName ID ID_NAME OF oClient REDEFINE BUTTON ID ID_NEXT OF oClient ACTION GoNext(oClients,oName) SELECT Sales // We select Sales to properly initialize the Browse REDEFINE LISTBOX FIELDS ID ID_SALES OF oClient ACTIVATE DIALOG oClient CENTERED NOWAIT ; VALID ( oClient := nil, .t. ) // Destroy the object SELECT Clients return nil function ChangeClient(oClients,oName) if oClients != nil cName = AllTrim( Clients->Last ) + ", " + Clients->First oName:Refresh() endif return nil function GoNext(oClients,oName) if oClients != nil oClients:oControl:GoDown() else SKIP if EoF() GO BOTTOM endif endif ChangeClient(oClients,oName) return nil /* * MENUITEM "&Browse..." ACTION HbDllEntry( "CusTeste" ) MESSAGE "Browse de Clientes" * Esta funcao foi chamada atraves de parametro da funcao exportavel hbDLLEntry() * Chamada indireta, pois a funcao abaixo passa por outra funcao para agir */ function CusTeste() USE Customer SHARED NEW ALIAS Clients Browse() CLOSE DATABASES return .t. /* * MENUITEM "&Customer..." ACTION CusTstBrw() MESSAGE "Browse de Clientes" * Esta funcao foi chamada dentro da DLL usando o proprio nome ao inves de * usar hbDLLEntry(), desta forma ficou mais legal */ function CusTstBrw() USE Sales SHARED NEW Browse() CLOSE DATABASES return .t. Dentro do código da DLL existem aplicativos que serão chamados pela aplicação principal, Customer(), CusTeste() e CusTstBrw(). Atentem para o seguinte trecho: #pragma BEGINDUMP ... void pascal __export HBDLLENTRY( char * cProcName ) ... void pascal __export CusTstBrw() ... #pragma ENDDUMP Vejam que HBDLLENTRY e CusTstBrw são exportadas, ou seja, são visíveis as chamadas à DLL. Então como compilar este .PRG e transformá-lo em uma .DLL? Eu usei o bom-e-velho BUILDH.BAT com algumas alterações, vejam os trechos que foram modificados: %hdir%\bin\harbour %1 /n /i%fwh%\include;%hdir%\include /w0 /p %3 /d__HARBOUR__ > comp.log IF ERRORLEVEL 1 GOTO COMPILEERRORS @type comp.log echo -O2 -e%1.exe -I%hdir%\include;%bcdir%\include %1.c > b32.bc %bcdir%\bin\bcc32 -M -c @b32.bc copy %bcdir%\lib\uuid.lib :ENDCOMPILE IF EXIST %1.rc %bcdir%\bin\brc32 -r -I%bcdir%\include %1 rem IF EXIST %1.rc %vcdir%\bin\rc -r -d__FLAT__ %1 echo %bcdir%\lib\c0d32.obj + > b32.bc Quem usa este .BAT dirá, mas não tem nada de diferente neste trecho, mas tem sim e está na última linha, onde se vê echo %bcdir%\lib\c0d32.obj + > b32.bc Quando compilamos nossos programas para gerar executáveis o arquivo c0w32.obj é o usado, mas neste caso usaremos o c0d32.obj. Outra linha alterada no nosso BUILDH.BAT é a linha de chamada do iLink32.exe if %GT% == gtgui %bcdir%\bin\ilink32 -Gn -aa -s -Tpd @b32.bc No lugar de -Gn -aa -s -Tpe eu alterei para -Gn -aa -s -Tpd, onde e é para EXE e d é para DLL. Bom, depois de gerada a DLL é possivel testá-la sem precisar do uso do aplicativo principal, bastando usar para isto o RunDLL32.exe do Windows, executando um comando simples: %windir%\System32\RunDLL32 rochadll.dll,CusTstBrw Leve em consideração que os testes foram feitos dentro da pasta SAMPLES do Fivewin, portanto as tabelas CUSTOMER.DBF e SALES.DBF serao usadas. Se a DLL foi bem gerada um browse aparecerá mostrando os registros da tabela. Agora vamos a parte do aplicativo principal. Este poderá ser compilado normalmente usando o BUILDH.BAT: rocha.prg /* * Jose Carlos da Rocha * Trabalho com DLL de codigo xBase para uso com Harbour * Sao Paulo - 09/09/2014 * Baseados nos exemplos BabuDLL e outros */ #include "FiveWin.ch" FUNCTION Main() local oWndMain, oBarMain DEFINE WINDOW oWndMain TITLE "Janela dentro do EXE" MDI MENU BuildMenuMain() COLOR "N/W" DEFINE BUTTONBAR oBarMain OF oWndMain SIZE 60, 60 2007 DEFINE BUTTON OF oBarMain ACTION WinExec( "RunDLL32.exe rochadll.dll,CusTstBrw" ) DEFINE BUTTON OF oBarMain ACTION UseDLL( "CusTstBrw", "rochadll.dll" ) SET MESSAGE OF oWndMain TO "Testing the FiveWin DLLs" CENTERED ACTIVATE WINDOW oWndMain MAXIMIZED VALID MsgYesNo( "Quer sair?" ) RETURN nil FUNCTION BuildMenuMain() local oMenu MENU oMenu MENUITEM "Administracao" MENU MENUITEM "&Clientes..." ACTION HbDllEntry( "Customer" ) MESSAGE "Manutencao de Clientes" MENUITEM "&Browse..." ACTION HbDllEntry( "CusTeste" ) MESSAGE "Browse de Clientes" MENUITEM "&Customer..." ACTION CusTstBrw() MESSAGE "Browse de Clientes" SEPARATOR MENUITEM "&Sair" ACTION oWnd:End() ; MESSAGE "Sair do sistema" ENDMENU oMenu:AddMdi() // Add standard MDI menu options ENDMENU return oMenu FUNCTION UseDLL( cFuncName, cDllName ) local hDLL, cFarProc hDLL = LoadLibrary( cDllName ) if hDll > 32 cFarProc := GetProcAddress( hDLL, "DLLSYMINIT", .T., _INT ) CallDLL( cFarProc ) Eval( &( "{||" + cFuncName + "() }" ) ) endif return nil //-------------------------------------------------------------------------// #include "dll.ch" DLL32 FUNCTION CusTstBrw() AS LONG PASCAL LIB "rochadll.dll" DLL32 FUNCTION HBDLLENTRY( cProc AS LPSTR ) AS LONG PASCAL LIB "rochadll.dll" DLL32 FUNCTION HBDLLENTRY2( cProc AS LPSTR, pItem1 AS LONG, pItem2 AS LONG ) AS LONG PASCAL LIB "rochadll.dll" DLL32 FUNCTION HBDLLENTRY3( cProc AS LPSTR, pItem1 AS _INT, pItem2 AS _INT ) AS _INT PASCAL LIB "rochadll.dll" Vejamos agora algumas caracteristicas: ... DEFINE BUTTON OF oBarMain ACTION WinExec( "RunDLL32.exe rochadll.dll,CusTstBrw" ) ... No trecho acima faço execução de uma função dentro da .DLL usando execução de aplicativo externo. ... DEFINE BUTTON OF oBarMain ACTION UseDLL( "CusTstBrw", "rochadll.dll" ) ... Neste trecho, usando funções do Harbour exemplifico como chamar uma função existente na .DLL. Esta função deve ser EXPORTável e para tal foi necessária a definição de chamada desta função: ... DLL32 FUNCTION CusTstBrw() AS LONG PASCAL LIB "rochadll.dll" ... Abaixo vemos as formas de chamar nossas funções usando HbDllEntry, mas particularmente acho feio assim: ... MENUITEM "&Clientes..." ACTION HbDllEntry( "Customer" ) MESSAGE "Manutencao de Clientes" MENUITEM "&Browse..." ACTION HbDllEntry( "CusTeste" ) MESSAGE "Browse de Clientes" ... A função HbDllEntry() enxerga as funções que não são EXPORTáveis. Vale lembrar que as .DLL não ficaram pequenas, mas o fator levado em consideração é que para a manutenção fica mais produtivo ter várias .DLLs no sistema e ao modificar uma ou outra, podemos atualizar somente elas sem prejuízo ao EXE principal. Outra coisa importante: As telas usadas no aplicativo, não importando qual .DLL poderá usá-la, deverão ser compiladas com o .EXE principal. O Harbour usado foi a versão 3.2-17626. O download deste trabalho encontra-se no 4shared.com. Tenho grande certeza, que seria possivel chamar código xBase contido nas .DLLs através de outras linguagens como Delphi ou Visual Basic. Vale a pena testar e retornar. Blz... rochinha 1 Quote Link to comment Share on other sites More sharing options...
rochinha Posted September 9, 2014 Author Report Share Posted September 9, 2014 Amiguinhos, Uma pequena manutenção deverá ser feita no código rochadll.prg. Na função hbDLLEntry(), a linha que tem um return 0; pode ser excluída sem prejuízo: void pascal __export HBDLLENTRY( char * cProcName ) { hb_itemDoC( cProcName, 0, 0 ); return 0; // -------------------- Retirar esta linha } aferra 1 Quote Link to comment Share on other sites More sharing options...
Alexandre Bassanezi Posted September 10, 2014 Report Share Posted September 10, 2014 Rochinha, bom dia. Você também pode utilizar o HBMK2 para criar a DLL, os parametros -hbdyn ou -hbdynvm fazem isto. Abs, Alexandre Quote Link to comment Share on other sites More sharing options...
rochinha Posted September 11, 2014 Author Report Share Posted September 11, 2014 Amiguinhos, Rochinha, bom dia. Você também pode utilizar o HBMK2 para criar a DLL, os parametros -hbdyn ou -hbdynvm fazem isto. Abs, Alexandre Eu não uso o HBMK2, ainda não tenhos as manhãs do barato. Mas, baseado no que foi apresentado, se puder postar um script, agradeço. @braços. Quote Link to comment Share on other sites More sharing options...
fladimir Posted September 11, 2014 Report Share Posted September 11, 2014 Rochinha, vou parabenizar vc pelo seu empenho e dedicação, alias diga-se de passagem, é constante, em compartilhar conquistas e vitórias q ampliam horizontes de muitos como pude ver em posts de colegas, q diferentes de mim, entenderam a aplicabilidade da sua contribuição. Peço desculpas pela minha ignorância e/ou falta de visão, mas qual seria a usabilidade/utilidade disto no dia a dia? Poderia citar um exemplo prático? []´s rochinha 1 Quote Link to comment Share on other sites More sharing options...
Alexandre Bassanezi Posted September 11, 2014 Report Share Posted September 11, 2014 bom dia! Ele é tão complicado como um simples comando hbmk2 seuprograma.prg Para criar a DLL neste caso, você usaria o comando hbmk2 seuprgdll.prg -hbdynvm Um exemplo de Script segue em anexo. Abs Alexandre fwh.zip rochinha 1 Quote Link to comment Share on other sites More sharing options...
rochinha Posted September 12, 2014 Author Report Share Posted September 12, 2014 Amiguinhos, Ale_Bass, Valeu! É que sou daquele tipo que gosta de ver todo o código que vai ser executado, tipo, prefiro um arquivo de lote, faço páginas de site no notepad, etc. Mas tem tempos que venho querendo usar o HBMK2 para simplificar a compilação de sistemas, ainda mais quando já está gigantesco o conjunto de arquivos .PRG e RC. Fladimir, imagine as duas situações: 1 - Você fez uma rotina show-de-bola e que seria uma maravilha para a comunidade, se não fosse pelo fato de que você usa o Harbour ano 1900 para Borland e alguém usa xHarbour ano 2030 com MingW. Na hora da compilação dá pau, falta, biblioteca, código C incompatível, etc e outros etc. 2 - Você tem um sistema monolítico, e está em pleno vapor de atualizações, manutenções, criações, possui um leque gigantesco de clientes e toda vez que precisa atualizar o cliente, precisa derrubar toda a rede e blábláblá. Se o seu sistema possui módulos em DLL você pode atualizar um ou outro sem comprometimento do restante. Se a sua rotina show-de-bola for usada por alguém ela não ficará somente no âmbito da linguagem, dependendo, pode ser acessada através de um aplicativo VisualBasic, Delphi, etc. Portanto, resta entender onde a tecnologia se aplica e no momento certo voce a usará. @braços. kapiaba 1 Quote Link to comment Share on other sites More sharing options...
kapiaba Posted September 12, 2014 Report Share Posted September 12, 2014 Rochinha: Você é GENIAL ou seria: BESTIAL? kkkkkkkkkkkkkkkkkkkk Aprendo muito com este kabra. Obg. abs. rochinha 1 Quote Link to comment Share on other sites More sharing options...
fladimir Posted September 12, 2014 Report Share Posted September 12, 2014 Vlw Rochinha perfeita a explicação, como sempre vc, assim como muitos outros colegas, contribui muito com a comunidade, somos gratos a sua dedicação e ajuda. []´s rochinha 1 Quote Link to comment Share on other sites More sharing options...
rochinha Posted September 15, 2014 Author Report Share Posted September 15, 2014 Amiguinhos, Apesar de ter iniciado o tópico, outro colega do Forum PC Toledo deu continuidade, testando com outros compiladores e obteve ótimos, senão excelentes resultados em relação ao uso de MSVC e MingW. Se alguém usa Fivewin e tem preferência por estes compiladores poderá fazer uso e entender o funcionamento da parafernália toda com estes compiladores. $u$$e$$o. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.