Problemas para descarregar .bpl ( UnloadPackage(); )
Olá, quero antes de mais nada dizer que procurei muito antes de postar aqui no forum, e quando digo que procurei, realmetente foi tempo, tem umas duas semanas que estou tentando terminar isso e nao consigo.
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:
em cada formulário filho [b:54c1d39d9f]MDIChild[/b:54c1d39d9f], eu criei uma pequena procedure que chama o form:
No evento OnClose dos Forms Filhos tenho o seguinte
no meu form Principal [b:54c1d39d9f]MDIForm[/b:54c1d39d9f], onde faço as chamadas dos filhos [b:54c1d39d9f]MDIChild[/b:54c1d39d9f] tenho assim:
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é +++
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
Curtidas 0
Respostas
Godzilla_xf
23/08/2008
Up...
GOSTEI 0
Romulocpd
23/08/2008
Olá,
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!
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
Godzilla_xf
23/08/2008
Olá,
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!
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
Romulocpd
23/08/2008
Depende da forma que trabalha. Geralmente usamos 1 formulario em um determinado pacote. Então quando for fechar este form o módulo deve ser descarregado.
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
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
Godzilla_xf
23/08/2008
Depende da forma que trabalha. Geralmente usamos 1 formulario em um determinado pacote. Então quando for fechar este form o módulo deve ser descarregado.
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
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
Godzilla_xf
23/08/2008
Olá, eu só queria uma ideia de como chamar uma funcao para descarregar um bpl logo apos ter fechado o form, correspondente ao bpl. não quero nada pronto nao, somente uma ideia.
por exemplo:
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.
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
Godzilla_xf
23/08/2008
up..
GOSTEI 0
Godzilla_xf
23/08/2008
up...
GOSTEI 0
Marco Salles
23/08/2008
No onclosse desse forms (filhos que estão na bpl) mande uma mensagem
para a aplicação principal... Esta mensagem sera interceptada na Aplicação Principal e voce podera descarregar esta Packages
Exemplo
e finalmente
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]
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
Godzilla_xf
23/08/2008
[quote:d64a1325a2=´Marco Salles´]No onclosse desse forms (filhos que estão na bpl) mande uma mensagem
para a aplicação principal... Esta mensagem sera interceptada na Aplicação Principal e voce podera descarregar esta Packages
Exemplo
e finalmente
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.
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
Godzilla_xf
23/08/2008
Olá, [b:521907d64a]Marco Salles[/b:521907d64a], obrigado pela ajuda amigo, fico grato desde já, e queria postar algumas coisas que precisei arrumar para funcionar sua dica.
1. No Form Principal precisei declarar uma Constante do Tipo WM_USER; por exemplo.
depois criei uma procedure parecida com a sua assim:
depois nos forms Filho fiz assim
redeclarei a mesma constante do form principal.
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é ++++
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
Marco Salles
23/08/2008
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 UserMessage, vou procurar sobre isso.
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
Godzilla_xf
23/08/2008
[quote:9e65814a71=´Marco Salles´]
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]
// 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
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]
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 UserMessage, vou procurar sobre isso.
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
Márcio
23/08/2008
Srs, estou com exatamente o mesmo problema.
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?
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