델파이에서 일반적인 창의 구현
Delphi의 VCL 라이브러리에서 사용 및 구현의 편의 를 위해 응용 프로그램 객체 응용 프로그램은 메시지 응답을 처리하기위한 숨겨진 창을 만듭니다. 이 창은 VCL로 개발 된 프로그램이 다른 창과 정상적으로 배열되지 않고 타일을 할 수없는 것처럼 다소 변형되는 것처럼 보이게합니다. VCL의 심층 분석을 통해이 기사는 원래 프로그래밍 방법을 변경하지 않고 3 줄의 코드를 애플리케이션 프로젝트 파일로 만 수정하여 문제를 해결할 수있는 솔루션을 제공합니다.
키워드 VCL, 일반 창, 정규화
1 소개
Delphi가 제공하는 VCL 클래스 라이브러리에 작성된 Windows 응용 프로그램에는 표준 Windows 창과 분명히 다른 고유 한 기능이 있습니다. 기본 창의 시스템 메뉴는 작업 표시 줄의 시스템 메뉴와 다릅니다. 일반적으로 기본 창의 시스템 메뉴에는 6 개의 메뉴 항목이 있으며 작업 표시 줄 시스템 메뉴에는 3 개의 메뉴 항목 만 있습니다. 실제로, 우리는 VCL로 개발 된 프로그램이 다음과 같은 당혹감을 가지고 있음을 발견했습니다.
1) 충분히 아름답 지 않습니다. 이것은 표준과 일치하지 않으면 자연스럽게 약간 변형 된 것처럼 보일 것입니다.
2) 기본 창이 최소화 될 때 애니메이션 효과가 없습니다.
3) 창을 다른 창과 함께 정상적으로 배열 할 수없고 타일을 할 수 없습니다.
4) 작업 표시 줄 시스템 메뉴는 우선 순위가 가장 높습니다. 모달 창이있을 때, 모달 창의 설계와는 반대로 전체 프로그램을 최소화 할 수 있습니다.
기본 창에서 애니메이션 효과를 최소화하는 문제는 Showwinnoanimate 기능에 의해 Forms.pas 델파이 5.0 이후 버전에서 해결되었지만 나머지 문제는 항상 존재했습니다. 이것은 대부분의 경우 응용 프로그램에 아무런 영향을 미치지 않지만, 전문적인 영향을 추구하는 일부 상황에서는 실제로 용납 할 수 없습니다. C ++ Builder 및 Delphi는 동일한 클래스 라이브러리 세트를 사용하기 때문에 위의 문제는 C ++ Builder를 사용하여 작성된 Windows 응용 프로그램에도 존재합니다.
나는 이전 기사 에서이 문제를 논의했으며 (Forrest Gump의 집에서 찾을 수 있음), 당시의 이야기는 기본적으로 속임수로 보였고, 그 방법을 우연히 발견했습니다. 이 기사의 과제는 VCL 클래스 라이브러리를 분석하여이를 수행하는 원칙을 설명한 다음 3 줄의 코드 만 사용하여 델파이 에서이 "비정상적인 창"의 문제를 완전히 해결하는 방법을 제공하는 것입니다.
2 원칙
2.1 응용 프로그램 생성 프로세스
다음은 일반적인 응용 프로그램 Delphi 프로젝트 파일입니다. 처음부터 응용 프로그램 객체의 초기화 방법에 대한 참조가 있음을 알았습니다.
프로그램 프로젝트 1;
용도
형태,
'unit1.pas'{form1} 의 unit1;
{$ r *.res}
시작하다
application.initialize;
application.createform (tform1, form1);
application.run;
끝 .
숨겨진 창은 응용 프로그램 객체에 의해 생성되므로 응용 프로그램 객체는 어디에서 왔습니까? Delphi의 코드 편집 창에서 CTRL을 눌러 누르고 응용 프로그램을 클릭하면 응용 프로그램 객체가 양식에 정의 된 여러 전역 객체 중 하나임을 알 수 있습니다. 이것으로는 충분하지 않습니다. 우리가 알고 싶은 것은 응용 프로그램 객체가 생성 된 위치입니다. tapplication 클래스의 인스턴스는 우리가 참조하기 전에 성공적으로 만들어야하기 때문입니다.
그것에 대해 생각해보십시오. 응용 프로그램에 실행될 코드가 있습니까? 그건 그렇고, 그것은 초기화 코드 세그먼트의 코드입니다. VCL 소스 코드를 신중하게 디버깅 한 후 VCL의 많은 장치에 초기화 코드 세그먼트가 있다는 것을 알 수 있습니다. 모든 초기화 조치. 초기화 메소드는 응용 프로그램을 초기화하는 것이므로 응용 프로그램 객체가 특정 장치의 초기화 스 니펫에서 생성되는 것이 분명합니다.
키워드 "tapplication.create"로 VCL 소스 코드 디렉토리에서 검색하면 Controls.pas 단위에서 응용 프로그램 객체를 생성하는 코드를 찾았습니다. Controls.PAS 단위의 초기화 코드 세그먼트에는 InitControls 절차에 대한 호출이 있으며 InitControls의 구현은 다음과 같습니다.
단위 제어;
…
초기화
...
initcontrols;
절차 initcontrols;
시작하다
...
마우스 : = tmouse.create;
화면 : = tscreen.create ( nil );
응용 프로그램 : = tapplication.create ( nil );
...
끝 ;
좋아,이 시점에서 우리의 분석은 첫 번째 단계를 완료했습니다. 비정상적인 Windows의 문제를 해결하려면 응용 프로그램 객체를 초기화하기 전에 한 가지 작업을 수행해야하므로 응용 프로그램의 초기화 프로세스를 이해하는 것이 매우 중요합니다.
2.2 ISLIBRARY 변수
Islibrary 변수는 System.PAS 단위에 정의 된 글로벌 플래그 변수 중 하나입니다. Islibrary의 값이 참이면 프로그램 모듈이 동적 링크 라이브러리라는 것을 의미합니다. 그렇지 않으면 실행 가능한 프로그램입니다. VCL 클래스 라이브러리의 일부 프로세스는이 플래그 변수의 다른 값을 기반으로 다른 작업을 완료합니다. 즉,이 변수는 델파이의 비정상적인 창 문제를 해결하는 데 중요한 역할을합니다.
앞에서 언급했듯이 편의를 위해 응용 프로그램 객체가 초기화 될 때 보이지 않는 창이 만들어졌지만 (즉, 스파이 ++와 같은 도구로 보이는 클래스 이름으로서 "tapplication"이있는 창)이지만,이 창의 보이지 않기 때문입니다. 델파이로 개발 된 프로그램은 많은 이상을 보여줍니다. 자,이 보이지 않는 창을 제거하고 (작업 표시 줄 시스템 메뉴를 동시에 제거 할 수 있다면) 응용 프로그램 기본 창으로 바꾸면 모든 문제가 해결되지 않습니까?
말하기는 간단하지만 VCL 소스 코드를 구현하려면 주요 수술이 필요합니까? 마트를 말 앞에 약간 넣는 것이 아닐까요? 물론 대답은 아니오입니다. 그렇지 않으면이 기사를 사용할 수 없었을 것입니다. 내가 여기서 말하고 싶은 것은 다음 분석에서, 우리는 소위 "프로그래밍 방식이 하나의 마음에있다"는 것을 알게 될 것입니다. Tapplication Design에서 의도하지 않은 버드 나무 심기의 관행은 실제로이 문제에 대한 해결책을 남깁니다. 인터페이스. 소스 코드 분석을 수행하지 않으면 원으로 돌아가야 할 수도 있지만 실제로 천재 디자인이 우리를 더 이상 우리를 떠나게합니다.
Tapplication 클래스의 생성자 작성을 열면 그러한 코드 라인이 있습니다.
생성자 tapplication.create (aowner : tcomponent);
시작하다
...
Islibrary 가 아니라면 CreateHandle ;
...
끝 ;
여기서는 프로그램 모듈이 동적 링크 라이브러리가 아닌 경우 CreateHandle을 실행하고 CreateHandle에서 수행 한 작업은 도움의 다음과 같습니다. "응용 프로그램 창이 없으면 Application Program"을 작성하십시오. Window "위에서 언급 한 보이지 않는 창입니다.이 창은 범인입니다. Tapplication 클래스에서 Fhandle 변수는 창 손잡이를 저장하는 데 사용됩니다. 동적 링크 라이브러리에서는 메시지 루프가 일반적으로 필요하지 않지만 응용 프로그램 객체를 사용하여 VCL을 사용하여 동적 링크 라이브러리를 개발하기 때문에 이는 Islibrary의 가치에 따라 다른 동작을 완료하는 것입니다. 좋아, 우리는 단지 응용 프로그램 객체를 속이고, 만들기 전에 Islibrary를 true에 할당하고, CreateHandle의 실행을 필터링 하고이 성가신 창을 제거하면됩니다.
Islibrary에 할당 된 코드는 또한 초기화 코드 세그먼트의 코드가 포함 된 단위의 순서로 실행되므로 특정 장치의 초기화 코드 세그먼트에 배치되어야합니다. 응용 프로그램 객체는 프로젝트 파일에서 생성됩니다.이 장치가 다음과 같이 양식 단위 앞에 할당 코드를 포함하는 장치를 배치해야합니다 (단위의 이름이 UnitDllexe.pas라고 가정).
프로그램 템플릿;
용도
'unitdllexe.pas' 의 unitdllexe
형태,
'formmain.pas'{mainform} 의 formmain
...
UnitDllexe.pas 코드 목록은 다음과 같습니다.
단위 itdllexe;
인터페이스
구현
초기화
Islibrary : = 참;
// ApplCiation 객체에 동적 링크 라이브러리이며 숨겨진 창을 만들 필요가 없다고 말합니다.
끝 .
좋아, 컴파일하고 실행합니다. 창. 그러나 문제는 창을 최소화 할 수 없다는 것입니다. 무슨 일이야? 여전히 오래된 방법입니다.
2.3 메인 창 최소화
최소화는 시스템 명령에 속하며 궁극적으로 창을 최소화하기 위해 API 함수 DEFWINDOWPROC라고 불리우므로 TCUSTOMFORM에서 WMSSCOMMAND 함수를 wm_syscommand 메시지에 응답하는 기능을 발견하여 최소화 된 메시지를 응용 프로그램으로 변경하도록 명확하게 기록합니다. .wndproc 처리 :
절차 tcustomform.wmsyscommand ( var message : twmsyscommand);
시작하다
메시지 와 함께
시작하다
if (cmdtype 및 $ fff0 = sc_minimize) 및 (application.mainform = self) 그런 다음
application.wndproc (tmessage (메시지))
...
끝 ;
끝 ;
application.wndproc에서 최소화 된 메시지에 응답하여 최소화 된 응용 프로그램 방법이 호출되므로 문제의 요점은 최소화 프로세스에 있어야합니다.
절차 tapplication.wndproc ( var 메시지 : tmessage);
...
시작하다
...
메시지 와 함께
사례 msg
WM_SYSCOMMAND :
사례 wparam 및 $ fff0
sc_minimize : 최소화;
SC_RESTORE : 복원;
또 다른
기본;
...
끝 ;
마지막으로, tapplication을 찾으십시오. 매니미 화하면 모든 것을 이해할 수 있습니다. 여기에서 defwindowproc 기능에 대한 호출은 어떤 영향을 미치지 않습니까? 우리는 전에 응용 프로그램 객체를 속이고, CreateHandle의 호출을 필터링하고 응용 프로그램 객체의 메시지에 응답하는 데 필요한 창을 만들지 않았으며, 핸들이 0이고, 호출은 물론 실패했습니다. Fhandle을 기본 응용 프로그램 창에 가리킬 수 있으면 문제가 해결됩니다.
절차 tapplication.minimize;
시작하다
...
defwindowproc (fhandle, wm_syscommand, sc_minimize, 0);
// 여기서 fhandle 값은 0입니다
...
끝 ;
3 구현
보할 랜드 천재의 의도하지 않은 디자인은 다시 한 번 우리가 문제를 해결할 수있게 해주었다. 이전 분석에서 VCL로 개발 된 동적 링크 라이브러리에는 Windows 메시지를 수신 할 숨겨진 창이 없지만 (CreateHandle이 실행되지 않음), 동적 링크 라이브러리에는 창을 표시하려면 필요합니다. 부모 창. 이 문제를 해결하는 방법? VCL 디자이너는 보이지 않는 창 핸들을 쓰기 가능한 것으로 보유하는 Fhandle 변수를 설계하므로 실제로 Fhandle에 값을 할당하여 표시 해야하는 어린이 창에 부모 창을 제공 할 수 있습니다. 예를 들어, 동적 링크 라이브러리 플러그인에서 양식을 표시하는 것은 일반적으로 기본 모듈 실행 파일의 동적 링크 라이브러리의 함수를 통해 응용 프로그램 객체의 핸들을 전달하고이를 Application.handle of the Dynamic에 할당합니다. 기본 모듈 실행 파일의 링크 라이브러리와 유사한 동적 링크 라이브러리의 응용 프로그램에 할당하십시오.
절차 setApplicationHandle (mainAppwnd : hwnd)
시작하다
application.handle : = mainAppwnd;
끝 ;
좋아, anplication.handle은 실제로 메시지에 응답하는 데 내부적으로 사용되는 창 핸들 일 뿐이며 생성되어야 할 보이지 않는 창이 우리에 의해 제거되었으므로 대체 할 수 있도록 창 핸들 만 제공하면됩니다. 원래 불필요한 창의 손잡이를 숨기는 것이 충분합니까? 그런 창문은 어디에서 찾을 수 있습니까? 응용 프로그램의 기본 창이 최선의 선택이므로 다음 코드를 사용할 수 있습니다.
프로그램 템플릿;
용도
'unitdllexe.pas' 의 unitdllexe
형태,
'formmain.pas'{mainform} 의 formmain;
{$ r *.res}
시작하다
application.initialize;
application.createform (tformmain, formmain);
application.handle : = formmain.handle;
application.run;
끝 .
따라서 모든 문제가 해결되었습니다. VCL 소스 코드를 수정할 필요가 없으며 원래 프로그램을 수정할 필요가 없습니다. 프로젝트 파일에 두 줄의 코드를 추가하십시오. 응용 프로그램 창이 표준 Windows 창만큼 정상적인 코드 라인 중 3 줄입니다.
1) 작업 표시 줄과 윈도우 제목 표시 줄에는 일관된 시스템 메뉴가 있습니다.
2) 기본 창이 최소화 될 때 애니메이션 효과가 있습니다.
3) 창을 다른 창으로 정상적으로 배열하고 기울어 질 수 있습니다.
4) 모달 창이있을 때는 부모 창에서 작동 할 수 없습니다.
위 구현 코드는 모든 버전의 델파이에 사용됩니다.