작가: 조우 페이(Zou Fei)
이메일: [email protected]
홈페이지 : http://www.atechsoft.com/people/zouf/ 델파이를 사용하다 보면 필연적으로 이상한 문제가 많이 발생하게 되며 델파이의 문서는 의외로 적기 때문에 혼자서 천천히 요약할 수 밖에 없기 때문에 (이후 그것은 단지 흩어져 있는 세부 사항일 뿐이고, 글을 쓰는 데 많은 노력을 기울이지 않았습니다. 약간 지저분할 수도 있지만 이해할 수 있어야 합니다. ;-)). 만약: 1. 다음 문제에 대한 더 나은 해결책이 있다면 csdn에서 나와 내 친구들에게 알려주십시오. 2. 다른 질문이 있으면 문제와 답변을 나열하고 csdn에서 나와 내 친구들에게 알려주십시오. 소통이 모든 것을 창조합니다!
텍스트: Q: Delphi DLL로 만든 Form이 Exe에서 ShowModal인 경우 작업 표시줄에 두 개의 아이콘이 나타납니다. 이 문제를 해결하는 방법? A: 다음은 DLL에 양식을 배치하는 일반적인 방법입니다. DLL: function ShowFrm: TModalResult; stdcall;beginForm1 := TForm1.Create(Nil); finallyForm1.Free;end;main EXE: 함수 ShowFrm: TModalResult 외부; 'TestDLL.dll';...begin...ShowFrm;...end 이렇게 생성된 DLL의 양식은 기본 응용 프로그램과 함께 다른 아이콘을 표시합니다. 그 이유는 Delphi에서 DLL에 대해 다른 응용 프로그램이 생성되기 때문입니다. 응용 프로그램은 작업 표시줄 아이콘을 표시합니다. 해결 방법: 다음과 같이 기본 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: function ShowFrm(app: TApplication): TModalResult; external 'TestDLL.dll';…begin…ShowFrm(Application);…end. 참고: DLL의 애플리케이션과 EXE의 애플리케이션이 있습니다. 여전히 몇 가지 차이점이 있습니다. Forms.pas의 코드를 살펴보세요. 생성자 TApplication.Create(AOwner: TComponent);begin...IsLibrary가 아니면 CreateHandle;...end;DLL의 응용 프로그램에 핸들이 없으므로 메시지 루프 처리가 수행되지 않는 것으로 알 수 있으며 이 역시 맞습니다. Q: Delphi에서 DLL에 문제가 자주 발생합니다! A: 문제가 발생하는 이유는 델파이 자체의 메모리 관리 메커니즘 때문입니다. 예: DLL에서 객체를 생성합니다: x := TClass.Create(Application); 이때 Delphi는 자동으로 Free를 수행합니다. 주소 공간이 만료되었을 수 있으므로(운영 체제에 따라 다를 수 있음) x의 릴리스 작업은 예외를 발생시킵니다. 또 다른 예: EXE에서 개체를 생성하고 DLL을 DLL의 로컬 변수로 전달합니다. DLL이 삭제되면 Delphi는 범위를 벗어난 모든 변수를 자동으로 해제하므로 EXE에서 이를 다시 개체로 사용하면 예외가 발생합니다. 일반적으로 문제는 "스마트" Delphi 컴파일러의 메모리 관리 메커니즘과 Windows의 DLL 추가/언로드 메커니즘으로 인해 발생하며, 이로 인해 DLL과 EXE에서 메모리 액세스 충돌이 발생합니다. 해결 방법: (다음 원칙을 따르면 대부분의 문제를 피할 수 있습니다.) 1. DLL과 EXE 사이에서 Delphi의 자동 메모리 관리 메커니즘을 사용하지 마십시오. 예를 들어 위의 경우 x := TClass.Create(Application); TClass.Create(nil); 이러한 방식으로 애플리케이션은 더 이상 이를 해제하지 않습니다. 물론 프로그래머가 직접 해제해야 합니다. 2. DLL과 EXE 사이에 동일한 개체를 가리키는 다른 포인터가 없도록 하십시오. 예를 들어, DLL에서 x는 TClass 개체를 가리키고 EXE에서는 y가 TClass 개체를 가리킵니다. 이러한 방식으로 한쪽의 메모리가 해제되면 다른 쪽의 메모리가 유효하지 않게 됩니다. 3. 기타... Q: 주기적 작업을 수행하는 스레드는 잠시 일시 중지한 다음 계속 실행해야 합니다. 그런데 이때 스레드를 중지해야 하는 경우(예: 프로세스가 종료됨) 어떻게 될까요? A: 해결 방법 1: 스레드에서 Sleep을 통해 주기적 루핑을 수행합니다. (Sleep을 통해 스레드가 일시정지된 경우 Resume 및 기타 메소드를 통해 스레드를 부활시킬 수 없습니다.) KillThread를 통해 스레드를 종료합니다. 이 방법은 가장 간단한 방법이지만 너무 조악하고 문제가 발생할 수 있습니다. (KillThread는 Windows에 권장되지 않는 API입니다.) 해결 방법 2: 스레드를 일시 중단하고 스레드 외부에 타이머를 전달한 후 가끔씩 다시 시작합니다. 코드는 다음과 같습니다. // ThreadPROcedure Execute;beginwhile not Terminating dobegin... // 처리 코드 Suspend;end;end;// 외부 // 타이머 프로시저 OnTimer(Sender: Tobject);beginthd.Resume;end;// 스레드를 종료하려면 Place...thd.Resume;thd.Terminate;thd.WaitFor; 일반적으로 스레드를 종료한 후 스레드가 실제로 종료되었는지 확인하려면 WaitFor를 사용해야 합니다. ...문제: 스레드와 외부 사이의 결합이 너무 강하고, 스레드의 연산 주기도 외부 타이머를 통해 결정되어야 합니다. 해결 방법 3(이것이 제가 생각하는 가장 좋은 방법입니다): 세마포어를 통해 스레드를 일시 중지합니다. // ThreadTMyThread = class(TThread)private 이벤트: TEvent;protected 프로시저 실행; 공개 생성자 Create(loginInfo: TLoginInfo); 소멸자 소멸; 프로시저 SetEvent;end;{ TMyThread }생성자 TMyThread.Create(loginInfo: TLoginInfo);이벤트 시작 := TEvent.Create(nil, True, True, 'EventName');end;destructor TMyThread.Destroy;begin Event.Free; 상속됨;end;프로시저 TMyThread.Execute;begin 상속됨; 종료되지 않은 동안 do start // ... Event.WaitFor(10000); end;end;procedure TMyThread.SetEvent;begin Event.SetEvent;end;스레드를 중단해야 하는 프로그램의 경우 다음 코드만으로 충분합니다. ...thd.Terminate;thd.SetEvent;thd.WaitFor;...end;