Автор: Цзоу Фэй
Электронная почта: [email protected]
Домашняя страница: http://www.atechsoft.com/people/zouf/ В процессе использования Delphi вы неизбежно столкнетесь со множеством странных проблем, а документации по Delphi также на удивление мало, поэтому я могу лишь медленно резюмировать ее самостоятельно. , так и есть (Поскольку это просто разрозненные детали, я не тратил особых усилий на написание, может быть немного сумбурно, но должно быть понятно ;-)). Если: 1. Если у вас есть лучшее решение следующей проблемы, сообщите мне и моим друзьям на csdn. 2. Если у вас есть другие вопросы, перечислите проблемы и свои ответы и сообщите мне и моим друзьям на csdn. Общение создает все!
Текст: Вопрос: Если форма, созданная в Delphi DLL, является ShowModal в Exe, на панели задач появятся два значка. Почему? Как решить эту проблему? О: Ниже приведен типичный метод размещения формы в DLL: DLL: function ShowFrm: TModalResult;beginForm1 := TForm1.Create(Nil); функция ShowFrm: TModalResult внешний; 'TestDLL.dll';…begin…ShowFrm;…end. Форма в DLL, созданная таким образом, будет отображать другой значок с основным приложением. Причина в том, что для DLL будет создано другое приложение в Delphi. Приложение отобразит значок на панели задач. Решение: передайте приложение основного EXE-файла в DLL основного приложения следующим образом: DLL: function ShowFrm(app: TApplication): TModalResult; stdcall;varoldApp: TApplication;beginoldApp := Application;Application := app;Form1 : = TForm1.Create(Nil);tryForm1.ShowModal;finallyForm1.Free;end;Application := oldApp;end;Main EXE: функция ShowFrm(app: TApplication): TModalResult; внешний 'TestDLL.dll';…begin…ShowFrm(Application);…end. Примечание. Приложение в DLL и приложение в EXE. все еще есть некоторые различия, посмотрите код в Forms.pas: конструктор TApplication.Create(AOwner: TComponent);begin…если не IsLibrary, то CreateHandle;…end;Может быть известно, что Приложение в DLL не имеет Handle, поэтому обработка цикла сообщений выполняться не будет, что тоже правильно. Вопрос: Часто возникают проблемы с DLL в Delphi! О: Причиной возникновения проблемы является собственный механизм управления памятью Delphi. Например: Создайте объект в DLL: x := TClass.Create(Application); В это время Delphi автоматически освободит адресное пространство. Возможно, истек срок действия адресного пространства (в разных операционных системах они будут разными), поэтому операция освобождения x будет выполнена. вызвать исключение. Другой пример: создайте объект в EXE и передайте DLL в качестве локальной переменной в DLL. Когда DLL будет уничтожена, Delphi автоматически освободит все переменные, выходящие за пределы области видимости, поэтому, если вы снова используете этот объект в EXE, появится объект. будет выброшено исключение. Вообще говоря, проблема связана с механизмом управления памятью «умного» компилятора Delphi и механизмом добавления/выгрузки DLL Windows, что приводит к конфликтам доступа к памяти в DLL и EXE. Решение: (Большинства проблем можно избежать, если следовать следующим принципам) 1. Между DLL и EXE старайтесь не использовать механизм автоматического управления памятью Delphi. Программист отвечает за жизненный цикл объекта. Например: для приведенного выше x := TClass.Create(Application); TClass.Create(nil); Таким образом, приложение больше не будет его освобождать. Разумеется, программист должен освободить его сам. 2. Старайтесь избегать наличия разных указателей, указывающих на один и тот же объект между DLL и EXE. Например, в DLL x указывает на объект TClass, а в EXE y указывает на объект TClass. Таким образом, освобождение памяти на любой стороне приведет к тому, что память на другой стороне станет недействительной. 3. Другие... Вопрос: Поток, выполняющий периодические задачи, должен на мгновение приостановиться, а затем продолжить работу. Но что, если в это время поток необходимо остановить (например, процесс завершился)? Ответ: Решение 1. Выполните периодический цикл перехода в режим сна в потоке. (Если поток приостановлен из-за режима сна, его нельзя возобновить с помощью Resume и других методов.) Завершите поток с помощью KillThread. Это самый простой метод, но он слишком груб и может вызвать проблемы (KillThread — это API, не рекомендуемый для Windows). Решение 2. Приостановите поток, передайте таймер за пределы потока и время от времени возобновляйте работу. Код выглядит следующим образом: // ThreadPROcedure Execute;begin while not Termination dobegin... // Код обработки Suspend;end;end;// Вне // Процедура таймера OnTimer(Sender: Tobject);beginthd.Resume;end;// Чтобы завершить поток Place...thd.Resume;thd.Terminate;thd.WaitFor; // Обычно после завершения потока вам необходимо использовать WaitFor, чтобы подтвердить, что поток действительно завершился. ...Проблема: связь между потоком и внешним миром слишком сильная, и даже рабочий цикл потока приходится определять с помощью внешнего таймера. Решение третье (это лучший способ, который я придумал): приостановить поток через семафор. // ThreadTMyThread = class(TThread)private Event: TEvent;защищенная процедура Execute; override;публичный конструктор Create(loginInfo: TLoginInfo); деструктор Destroy; override; TLoginInfo);begin Event:= TEvent.Create(nil, True, True, 'EventName');end;деструктор TMyThread.Destroy;begin Event.Free; inherited;end;procedure TMyThread.Execute;begin inherited; while not Termination do Begin // ... Event.ResetEvent; Event.WaitFor(10000); end;end;procedure TMyThread.SetEvent;begin Event.SetEvent;end;Для программ, которым необходимо прерывать потоки, достаточно следующего кода: начать …thd.Terminate;thd.SetEvent;thd.WaitFor;…end;