Autor: Zou Fei
E-mail: [email protected]
Página inicial: http://www.atechsoft.com/people/zouf/ No processo de uso do Delphi, você inevitavelmente encontrará muitos problemas estranhos, e a documentação do Delphi também é surpreendentemente pequena, então só posso resumi-la lentamente sozinho , então existem (como são apenas detalhes dispersos, não me esforcei muito na escrita, pode ser um pouco confuso, mas deve ser compreensível ;-)). Se: 1. Se você tiver uma solução melhor para o problema a seguir, conte para mim e para meus amigos no csdn. 2. Se você tiver outras dúvidas, liste os problemas e suas respostas e conte para mim e para meus amigos no csdn. A comunicação cria tudo!
Texto: P: Se um Form feito em Delphi DLL for ShowModal em Exe, aparecerão dois ícones na barra de tarefas. Por quê? Como resolver este problema? R: A seguir está um método típico de colocar um formulário em uma DLL: DLL: function ShowFrm: TModalResult;beginForm1 := TForm1.Create(Nil); função ShowFrm: TModalResult; 'TestDLL.dll';…begin…ShowFrm;…end. O formulário na DLL criada desta forma exibirá outro ícone com a aplicação principal. O aplicativo exibirá um ícone na barra de tarefas. Solução: Passe a Aplicação do EXE principal para a DLL da aplicação principal, conforme a seguir: DLL: function ShowFrm(app: TApplication): TModalResult; stdcall;varoldApp: TApplication;beginoldApp := Application;Application := app;Form1 : = TForm1.Create(Nil);tryForm1.ShowModal;finalmenteForm1.Free;end;Aplicativo := oldApp;end;EXE principal: função ShowFrm(app: TApplication): TModalResult; externo 'TestDLL.dll';…begin…ShowFrm(Application);…end. ainda algumas diferenças, veja o código em Forms.pas: construtor TApplication.Create(AOwner: TComponent);begin…se não for IsLibrary then CreateHandle;…end;Pode-se saber que a Aplicação na DLL não possui Handle, portanto o processamento do loop de mensagens não será realizado, o que também é correto. P: Frequentemente ocorrem problemas com DLLs no Delphi! R: A razão pela qual o problema ocorre é o próprio mecanismo de gerenciamento de memória do Delphi. Por exemplo: Crie um objeto em uma DLL: x := TClass.Create(Application); Neste momento, o Delphi irá liberar automaticamente O espaço de endereço pode ter expirado (diferentes sistemas operacionais serão diferentes), então a operação de liberação de x será causar uma exceção. Outro exemplo: Crie um objeto no EXE, e passe na DLL como variável local na DLL Quando a DLL for destruída, o Delphi irá liberar automaticamente todas as variáveis que estão fora do escopo, então se você usar isso no EXE novamente o objeto, um objeto. exceção será lançada. De modo geral, o problema se deve ao mecanismo de gerenciamento de memória do compilador Delphi "inteligente" e ao mecanismo de adição/descarregamento de DLL do Windows, o que leva a conflitos de acesso à memória no DLL e no EXE. Solução: (A maioria dos problemas pode ser evitada desde que você siga os seguintes princípios) 1. Entre DLL e EXE, tente não usar o mecanismo de gerenciamento automático de memória do Delphi. O programador é responsável pelo ciclo de vida do objeto. Por exemplo: para o x := TClass.Create(Application); TClass.Create(nil); Dessa forma, o Aplicativo não irá mais liberá-lo. Claro, o próprio programador deve liberá-lo. 2. Tente evitar ponteiros diferentes apontando para o mesmo objeto entre a DLL e o EXE. Por exemplo, na DLL, x aponta para o objeto TClass, e no EXE, y aponta para o objeto TClass. Dessa forma, a liberação de memória em qualquer lado fará com que a memória do outro lado seja inválida. 3. Outros... P: Um thread que executa tarefas periódicas precisa fazer uma pausa por um momento e depois continuar em execução. Mas e se o thread precisar ser interrompido neste momento (por exemplo, o processo foi finalizado)? R: Solução 1: Execute loops periódicos através do Sleep no thread. (Se o thread for pausado durante a suspensão, o thread não poderá ser ressuscitado por meio de Resume e outros métodos.) Encerre o thread por meio de KillThread. Este é o método mais simples, mas é muito rudimentar e pode causar problemas (KillThread é uma API não recomendada para Windows) Solução 2: Suspender na thread, passar um timer fora da thread e Retomar de vez em quando. O código é o seguinte: // ThreadPRocedure Execute;beginwhile not Terminated dobegin... // Processando código Suspend;end;end;// Fora // Procedimento de temporizador OnTimer(Sender: Tobject);beginthd.Resume;end;// Para encerrar o tópico Coloque...thd.Resume;thd.Terminate;thd.WaitFor; Geralmente, após encerrar o thread, você deve usar WaitFor para confirmar se o thread realmente terminou. ...Problema: O acoplamento entre a rosca e o exterior é muito forte, e até o ciclo de operação da rosca tem que ser determinado através de um temporizador externo. Solução três (esta é a melhor maneira que pensei): Faça uma pausa no thread por meio de um semáforo. // ThreadTMyThread = class(TThread)private Event: TEvent;procedimento protegido Execute;construtor público Create(loginInfo: TLoginInfo sobrecarga; destruidor Destroy; end;{ TMyThread }construtor TMyThread.Create(loginInfo: TLoginInfo);begin Event := TEvent.Create(nil, True, True, 'EventName');end;destruidor TMyThread.Destroy;begin Event.Free; herdado;end;procedure TMyThread.Execute;begin herdado; enquanto não Terminado começa // ... Event.ResetEvent; end;end;procedure TMyThread.SetEvent;begin Event.SetEvent;end;Para programas que precisam interromper threads, apenas o seguinte código é suficiente: Begin …thd.Terminate;thd.SetEvent;thd.WaitFor;…end;