Fórum Problemas para descarregar .bpl ( UnloadPackage(); ) #362894
23/08/2008
0
Bem vou expor aqui minha situaçao, estou mudando um sistema que desenvolvi em modulos bpl, ou seja cada form da aplicaçao esta em um bpl separado, e [b:54c1d39d9f]O SISTEMA É EM MDI[/b:54c1d39d9f], com o sistema de carga [b:54c1d39d9f]Implicita[/b:54c1d39d9f], para carga [b:54c1d39d9f]Explicita[/b:54c1d39d9f], até ai tudo certo, vou mostrar como fiz até agora.
Como dito acima o sistema é em [b:54c1d39d9f]MDI[/b:54c1d39d9f], e ai esta meu grande problema, pois eu consigo chamar os forms tudo beleza, [b:54c1d39d9f][i:54c1d39d9f]mas preciso descobrir uma forma de descarregar os bpl´s assim que os forms forem fechados, coisa que naum estou conseguindo de forma nenhuma[/b:54c1d39d9f][/i:54c1d39d9f]. Por este motivo que estou postando aqui no forum na tentativa de obter ajuda de vc´s.
vou explicar como esta a forma de chamar os meus forms.
eu cocloquei em uma Unit para ficar mais claro o que eu fiz:
unit uGeral; interface uses SysUtils; type TModulo = record nome : string; modulo: HMODULE; end; var carregados: array of TModulo; procedure descarga(_bpl: string); stdcall; implementation procedure descarga(_bpl: string); stdcall; var i: Smallint; begin i := -1; for i := Low(carregados) to High(carregados) do begin if (carregados[i].nome = _bpl) then begin UnloadPackage(carregados[i].modulo); end; end; end; end.
em cada formulário filho [b:54c1d39d9f]MDIChild[/b:54c1d39d9f], eu criei uma pequena procedure que chama o form:
procedure chamar; stdcall; exports chamar; implementation procedure chamar; stdcall; begin if MyFormChild = nil then Application.CreateForm(TMyFormChild, MyFormChild) else with MyFormChild do begin Show; BringToFront; WindowState := wsNormal; end; end;
No evento OnClose dos Forms Filhos tenho o seguinte
procedure TMyFormChild.FormClose(Sender: TObject; var Action: TCloseAction); begin MyFormChild := nil; Action := caFree; end;
no meu form Principal [b:54c1d39d9f]MDIForm[/b:54c1d39d9f], onde faço as chamadas dos filhos [b:54c1d39d9f]MDIChild[/b:54c1d39d9f] tenho assim:
procedure TfrmPrincipal.este011Click(Sender: TObject); type TChamar = procedure; stdcall; var _Chamar: TChamar; i: Smallint; begin i := Length(carregados); SetLength(carregados, i + 1); carregados[i].nome := ´pkgTeste01.bpl´; carregados[i].modulo := LoadPackage(carregados[i].nome); if carregados[i].modulo > 0 then begin @_Chamar := GetProcAddress(carregados[i].modulo, ´chamar´); _Chamar; end; end;
Se eu chamar a procedure [b:54c1d39d9f]descarga(´pkgTeste01.bpl´);[/b:54c1d39d9f] de um botao qualquer depois que o form for fechado o pacote e descarregado normalmente, porem por exemplo se eu for colocar no evento OnDestroy do formulario que pertence a este bpl, o evento simplesmente nao acontece, nao funciona.
Estou precisando muito disso se alguem puder me dar uma força ficarei muito agradecido. Obrigado desde já... té +++
Godzilla_xf
Curtir tópico
+ 0Posts
25/08/2008
Godzilla_xf
Gostei + 0
26/08/2008
Romulocpd
Em um projeto pra Lafarge estamos trabalhando desta forma também. Só não estamos utilizando MDI.
O que fizemos:
Temos um type tipo o seu mas com:
Handle do pacote (HMODULE)
Formulario (TForm)
Guardamos isso não em array mas sim em uma TList que é mmmuiiittoo mais fácil de gerenciar.
E na hora de ´matar´ o objeto (carrego em abas os formulários) primeiro matamos a isntancia do formulario e depois fazemos o unloadpackage. Se não matar o formulario antes tem horas que dá pau!
Bom, tenta ae!
Gostei + 0
26/08/2008
Godzilla_xf
Olá, antes de mais nada muito obrigado pela sua atenção, mas estou com uma duvida, pelo que vc me falou preciso guardar o HMODULE certo, mas em que momento do processo eu mandaria descarregar o pacote.
vc poderia me dar uma pequena explanaçao???
se vc pude-se me dar uma ideia mais clara eu ficaria muito grato mesmo. Obrigado desde já.
Gostei + 0
26/08/2008
Romulocpd
No meu caso eu carrego os forms para abas e tenho o meu TList com estes dados de HMODULE e outros. Assim quando o cara vai fechar a aba, que é um form, eu sei que é a hora de fazer o UnloadPackage. No seu caso tem q ue ver como você trabalha.
Romulo
Gostei + 0
26/08/2008
Godzilla_xf
Entaum, eu trabalho da seguinte forma, possuo uma aplicaçao em [b:ace7055bda]MDI[/b:ace7055bda], sendo que cada um de meus forms, [b:ace7055bda]MDIChild[/b:ace7055bda], esta disposto dentro de um pacote [b:ace7055bda].bpl[/b:ace7055bda], dentro de cada form existe uma procedure que é exportada para todo o sistema, da seguinte forma:
Unit de um form MDIChild, exemplo.
unit uFormBpl2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm3 = class(TForm)
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
procedure me; stdcall;
exports
me;
implementation
procedure me; stdcall;
begin
if not Assigned(Form3) then
Application.CreateForm(TForm3, form3)
else
with form3 do
begin
show;
BringToFront;
WindowState := wsNormal;
end;
(* if not Assigned(Form3) then
Form3 := TForm3.Create(Application)
else
with Form3 do
begin
Show;
BringToFront;
WindowState := wsNormal
end;*)
end;
{$R *.dfm}
procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
Form3 := nil;
end;
end.
uma vez exportado pela are de exports do form eu faço o seguinte no form chamador(principal)
procedure TfrmPrincipal.este011Click(Sender: TObject); type TChamar = procedure; stdcall; var _Chamar: TChamar; i: Smallint; begin i := Length(carregados); SetLength(carregados, i + 1); carregados[i].nome := ´pkgTeste01.bpl´; carregados[i].modulo := LoadPackage(carregados[i].nome); if carregados[i].modulo > 0 then begin @_Chamar := GetProcAddress(carregados[i].modulo, ´chamar´); _Chamar; end; end;
até ai esta tudo certo, o sistema chama os forms de boa, inclusive como eu naum quero que ele crie mais um, quando se e clicado no mesmo botao duas vezes, ele chama diretinho o form novamente para tela.
O problema e na hora de descarregar, esta funcao que eu peguei de um colega de forum e dei uma adaptada para a minha realidade, funciona se eu chama-la de um outro lugar qualquer depois de ter fechado o form e passado [b:ace7055bda]nil[/b:ace7055bda] para ele, porem preciso que quando o form se feche ele ja descarregue o pacote correspondente, entende. E isso nao esta sendo feito.
Eu ja tentei colocar em OnDestroy, OnClose, e tals mas parece que a funcao nao se executa.
eu sei que e chato ficar pedindo as coisas para os outros, mas vc naum poderia dar um exemplo de codigo sem que comprometece o seu desenvolvimento.
Gostei + 0
27/08/2008
Godzilla_xf
por exemplo:
procedure descarregar; var _hnd: THandle; begin _hnd := GetModuleHandle(´MyPackage.bpl´); UnloadPackage(_hnd); end;
isso funciona bem de fora do form, porem se eu chamo esta funcao de dentro do form ele gera exception, devido ao fato do form ainda estar aberto.
Era somente ai que eu precisava de uma dica.
Gostei + 0
28/08/2008
Godzilla_xf
Gostei + 0
06/09/2008
Godzilla_xf
Gostei + 0
06/09/2008
Marco Salles
para a aplicação principal... Esta mensagem sera interceptada na Aplicação Principal e voce podera descarregar esta Packages
Exemplo
form Principal..
private
{ Private declarations }
procedure UserMessage (var Msg: TMessage);
procedure TForm1.UserMessage(var Msg: TMessage);
begin
//Aqui descarrega o seu Package
showmessage(´fechou´);
end; //Inclui nos Forms Filhos formHandle:THandle; MsgBack:integer;
//Ao cria este Formulários deve passar o Valor correto FormFilho.formHandle:=Handle; //do form Principal FormFilho.MsgBack:=wm_user;
e finalmente
// nos forms Filhos procedure TFormFilhos.FormClose(Sender: TObject; var Action: TCloseAction); begin //envia uma mensagem para o Form Principal postMessage (FormHandle, MsgBack,0, 0); end;
Acresdito que funciona .. A mensagem postMessage não é sincrona e será processada depois que o FormFilho for fechado
Agora é com voce atribuir e cetar corretamente essas propriedades [b:2e5b76b129]formHandle ,MsgBack[/b:2e5b76b129]
Gostei + 0
06/09/2008
Godzilla_xf
para a aplicação principal... Esta mensagem sera interceptada na Aplicação Principal e voce podera descarregar esta Packages
Exemplo
form Principal..
private
{ Private declarations }
procedure UserMessage (var Msg: TMessage);
procedure TForm1.UserMessage(var Msg: TMessage);
begin
//Aqui descarrega o seu Package
showmessage(´fechou´);
end; //Inclui nos Forms Filhos formHandle:THandle; MsgBack:integer;
//Ao cria este Formulários deve passar o Valor correto FormFilho.formHandle:=Handle; //do form Principal FormFilho.MsgBack:=wm_user;
e finalmente
// nos forms Filhos procedure TFormFilhos.FormClose(Sender: TObject; var Action: TCloseAction); begin //envia uma mensagem para o Form Principal postMessage (FormHandle, MsgBack,0, 0); end;
Acresdito que funciona .. A mensagem postMessage não é sincrona e será processada depois que o FormFilho for fechado
Agora é com voce atribuir e cetar corretamente essas propriedades [b:d64a1325a2]formHandle ,MsgBack[/b:d64a1325a2][/quote:d64a1325a2]
Nossa, muito obrigado amigo vou testar e assim que tiver uma posiçao posto a resposta para vc, desde já agradeço muito sua ajuda.
Gostei + 0
07/09/2008
Godzilla_xf
1. No Form Principal precisei declarar uma Constante do Tipo WM_USER; por exemplo.
depois criei uma procedure parecida com a sua assim:
const Msg = WM_USER; // Esta constante deve estar antes da declaraçao de type do form Principal. // em private ou public procedure UserMessage(var Message: TMessage); message Msg; // aqui a implementação procedure TfrmPrincipal.UserMessage(var (* Note aqui esta variavel Message *) Message: TMessage); begin UnloadPackage(MyHandle); end;
depois nos forms Filho fiz assim
redeclarei a mesma constante do form principal.
const Msg = WM_USER; // No OnDestroy do form filho coloquei assim procedure TTeste02.FormDestroy(Sender: TObject); var hnd: THandle; begin hnd := FindWindow(nil, PChar(Application.MainForm.Caption)); PostMessage(hnd, Msg, 0, 0); end;
e ai deu certo, agora so preciso implementar uma forma de passar um string com o nome do pacote que eu quero fechar para a procedure [b:521907d64a]UserMessage[/b:521907d64a], vou procurar sobre isso.
fico muito agradecido pela força que me deu, obrigado mesmo. vlw té ++++
Gostei + 0
08/09/2008
Marco Salles
Humm... Mas isto pode se feito com o Numero do Handle desses Packages
Voce deve usar o [b:0c20329f5c]Terceiro Parametro da Mensagem[/b:0c20329f5c]
procedure TForm1.UserMessage(var Msg: TMessage); var Hmod: HMODULE; begin Hmod := Msg.WParam; //Aqui esta a DICA... // Ai descarregar .. unLoadPackage(Hmod); end;
// No OnDestroy do form filho coloquei assim
procedure TTeste02.FormDestroy(Sender: TObject);
var
hnd: THandle;
begin
hnd := FindWindow(nil, PChar(Application.MainForm.Caption));
PostMessage(hnd, Msg, TerceiroParametro, 0);
//No terceiro Parametro voce usa o Hanlde no seu caso O
// modulo: HMODULE;
end;
E como voce obtem o modulo...
Ora passa ele na procedure Chamar... Crie um parametro para esta Procedure
Private Modulo: HMODULE;
procedure chamar(O Handle Da Package); stdcall; begin if MyFormChild = nil then begin Application.CreateForm(TMyFormChild, MyFormChild) ; Modulo:=O Handle Da Package; else with MyFormChild do begin Show; BringToFront; WindowState := wsNormal; end; end;
Da certim...
Gostei + 0
08/09/2008
Godzilla_xf
Humm... Mas isto pode se feito com o Numero do Handle desses Packages
Voce deve usar o [b:9e65814a71]Terceiro Parametro da Mensagem[/b:9e65814a71]
procedure TForm1.UserMessage(var Msg: TMessage); var Hmod: HMODULE; begin Hmod := Msg.WParam; //Aqui esta a DICA... // Ai descarregar .. unLoadPackage(Hmod); end;
// No OnDestroy do form filho coloquei assim
procedure TTeste02.FormDestroy(Sender: TObject);
var
hnd: THandle;
begin
hnd := FindWindow(nil, PChar(Application.MainForm.Caption));
PostMessage(hnd, Msg, TerceiroParametro, 0);
//No terceiro Parametro voce usa o Hanlde no seu caso O
// modulo: HMODULE;
end;
E como voce obtem o modulo...
Ora passa ele na procedure Chamar... Crie um parametro para esta Procedure
Private Modulo: HMODULE;
procedure chamar(O Handle Da Package); stdcall; begin if MyFormChild = nil then begin Application.CreateForm(TMyFormChild, MyFormChild) ; Modulo:=O Handle Da Package; else with MyFormChild do begin Show; BringToFront; WindowState := wsNormal; end; end;
Da certim...[/quote:9e65814a71]
Olá, eu ia postar aqui no forum uma resposta parecida com a sua, neste momento não vou poder mas assim que der eu vou postar como fazer isso na integra, em todos os foruns que eu postei esta mensagem, para que os colegas que ajudaram e os que possam vir a precisar disso tirem proveito dos nossos exemplos. Eu realmente com sua ajuda e com mais umas informaçoes que achei neste site: http://www.delphi3000.com/articles/article_574.asp?SK= consegui arrumar uma funçao que faça o que vc vc flw acima, fico muito feliz pela sua ajuda, vlw mesmo.
[b:9e65814a71]Obrigado mesmo pela força ai, à vc e a Todos que ajudaram.[/b:9e65814a71]
vlw [b:9e65814a71]Marco Salles[/b:9e65814a71]
Gostei + 0
04/08/2010
Márcio
Gostaria de verificar com os Srs, como fazem nos casos em que tem um pacote e diversos formulários dentro do mesmo, sendo que existe mais de um formulário aberto ao mesmo tempo (do mesmo pacote, ou de diversos pacotes).
Como vcs fazem para não ocasionar o erro de access violation ao sair do pacote (implementado conforme os posts anteriores)?
Exemplo: Tenho a tela A10 aberta 2x no programa e o usuário fecha uma das janelas, como fazer para descarregar o pacote e não dar violação de acesso?
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)