2014-09-19 7 views
6

Delphi XE6 및 VCL 스타일을 사용하고 있습니다. 나는 메인 애플리케이션과 dll을 가지고있다. 내 주요 응용 프로그램은 런타임 테마를 활성화하고 vcl 스타일 파일을 사용하고 있습니다. 나는 나의 DLL과 아주 비슷한 것을했다. 런타임 테마를 활성화하고 VCL.Themes, VCL.Styles를 VCL 스타일 파일과 함께 사용 및 리소스 파일에 추가했습니다. DLL이로드 될 때 리소스에서 VCL 스타일을로드하고 DLL GUI를 설정합니다. 기본 응용 프로그램과 DLL은 런타임 패키지로 빌드되지 않습니다.VCL 스타일의 DLL이 응용 프로그램의 TMenuItem에 영향을줍니다.

이제는 기본 스타일의 GUI를 사용하여 고유 한 스타일로 꾸며졌으며 DLL gui도 자신 만의 스타일로 스타일을 지정했습니다. 이 때까지 잘 작동하는 것 ...

메인 애플리케이션에서 버튼을 클릭하면 TPopupMenu가 열립니다. 메인 애플리케이션 스타일 대신 DLL GUI와 동일한 스타일로 스타일이 지정됩니다. 메뉴를 탐색 할 때도 AV를 받고 프로그램이 다운됩니다. 첨부 된 이미지를 살펴보십시오.

내가 뭘 잘못하고 있니? 내가 현재 볼 수있는 유일한 해결 방법은 다른 컨트롤에서 파생 된 내 자신의 사용자 지정된 TPopupMenu를 만드는 것입니다. enter image description here


나는 내 응용 프로그램과 비슷한 간단한 데모 프로그램을 준비했습니다. 자체 스타일의 호스트 응용 프로그램과 리소스에 스타일이 추가 된 DLL로 구성됩니다. 그것을 실행하고 팝업 버튼을 클릭 한 다음 팝업에서 무언가를 선택하십시오. 그것은 충돌하고 일부 StdWindowProc 또는 그런 식으로 중지됩니다. 또한 해당 메뉴에서 무언가를 선택하려고 할 때 윈도우 시스템 메뉴 (왼쪽 상단 모서리)로 이동하면 시스템 메뉴가 DLL GUI 및 충돌로 스타일 화된다는 것을 알 수 있습니다. RAR 파일 링크 : 당신의 도움에 대한 dropbox.com/sh/f2jmbsmw18akpyg/AAA6SWdBmVhf6n6K-mvYLLmua?dl=0

enter image description here

감사합니다.

+0

가장 가능성있는 설명은 런타임 패키지를 사용하지 않으면 모듈 사이의 경계를 넘어 VCL 객체를 전달한다는 것입니다. –

+1

내가 생각할 수있는 또 다른 가능성은 VCL 스타일이 아마도 flubs 리소스 열거를 코딩하고 전체 프로세스에서 리소스를 열거한다는 것입니다. 코드를 빠르게 검사하면 AutoDiscoverStyleResources가 True이면 문제가 될 수 있음을 알 수 있습니다. 'EnumModules'에 대한 그 호출은 나에게 조금 어색해 보인다. –

+1

이것을 디버깅 할 수 없다면 우리가 파헤쳐달라고 요청하는 것 같습니다. 그렇게하려면 문제를 나타내는 코드가 필요할 수 있습니다. –

답변

6

이것은 VCL 스타일과 메뉴 스타일 지정의 근본적인 문제입니다. 스타일링은 프로세스 와이드 후크로 구현됩니다. 특히 SetWindowsHookEx에 대한 호출로 TCustomStyleEngine.CreateSysHook에서 Vcl.Themes 단위로 CBT 후크를 설치했습니다. 실제로, 후크는 GUI 스레드에만 적용되지만 프로세스에 정확히 하나의 GUI 스레드가 있다는 점에서 프로세스 와이드입니다.

응용 프로그램에 VCL 인스턴스가 여러 개 (하나는 DLL에, 다른 하나는 응용 프로그램에 있음)에 두 개의 후크가 설치됩니다. 그것은 너무 많은 것이다. 가장 최근에 설치된 훅 (DLL이 발생)이 승리하기 때문에 DLL 메뉴 스타일이 실행 파일을 감염시키는 이유입니다. 그리고 왜 액세스 위반이 발생합니다. DLL이 실행 파일에 속한 메뉴에서 작동하려고합니다. 따라서 최선의 노력에도 불구하고 호스트 실행 파일에서 VCL 객체에 액세스하는 DLL 코드로 끝났습니다.

이 문제를 해결하고 두 모듈 모두에서 스타일을 지원하는 간단한 방법은 없습니다. 여기서 우리가 가진 것은 디자인의 근본적인 결과입니다. 이 시스템은 여러 VCL 인스턴스를 지원하도록 설계되지 않았습니다. 여러 모듈에서 VCL 스타일을 사용하려면 디자이너가 런타임 패키지를 사용해야합니다.

완전히 다른 스레드에서 DLL을 조작하여 약간의 마찰을받을 수 있다고 생각합니다. 그렇게하려면 VCL이 스레드에서 초기화되도록 다른 스레드에서 DLL을로드해야합니다. DLL에 대한 모든 호출은 해당 스레드에서 이루어져야합니다. 그리고 그 스레드에서 메시지 루프를 실행해야합니다. 당신이 그 일을 할 수 있을지도 모르지만 나는 그것을 의심합니다. 모든 조건을 언급하더라도 입력 큐 처리와 관련된 모든 종류의 문제를 나타내는 두 개의 GUI 스레드가 있다는 사실을 여전히 처리해야합니다.

아마도 다른 접근법은 DLL에서 후크를 제거하는 것입니다. DLL이 메뉴를 표시하지 않는 한, 그 훅을 제거하는 것으로 도망 갈 수 있습니다. 그것은 DLL에 의해 보여지는 메뉴들에 대한 스타일링을 불가능하게 할 것입니다.

DLL의이 버전 (다소 단순화 한 후)은 후크를 제거합니다.

library VCLStyleDLL; 

{$R 'Style.res' 'Style.rc'} 

uses 
    VCL.Styles, 
    VCL.Themes, 
    VCL.SysStyles; // to gain access to TSysPopupStyleHook 

{$R *.res} 

begin 
    TStyleManager.TrySetStyle('Glossy', false); 
    TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook); 
end. 

이 버전의 DLL에서는 호스트 실행 파일이 사용자가 설명한 문제가 발생하지 않습니다.

+0

데이빗 감사합니다. 이후 우리는 타사 AlphaControls를 사용하여 응용 프로그램을 스킨했지만 이제는 델파이 VCL 스타일을 사용하기로 결정했으며 그저 배후에있는 기술을 발견하고 있습니다. 내 게시물을 편집/검토하고이 주제를 더 읽기 쉽게 만들어 주셔서 감사합니다. 정말 감사. – Nix

+0

안녕하십니까. 정보를 제공하고 좋은 질문을하고 문제를 해결하기 위해 우리와 함께 일하는 훌륭한 일을 해주셔서 감사드립니다. Btw, 준비가되면 가장 좋은 것으로 판단되는 답변을 수락해야합니다. 너의 선택. –

+0

+1 우수 설명 :) –

7

David가 말한 것처럼 각 VCL 인스턴스는 팝업 메뉴 (# 32768)가 생성 될 때 감지하기 위해 후크를 설치하기 때문에 발생합니다. 따라서 두 개의 훅 인스턴스가 동시에 작동합니다.

해결 방법으로 Vcl.SysStyles 유닛에 정의 된 UnRegisterSysStyleHook 함수를 사용하여 dll (또는 응용 프로그램)에서 popupmenu 스타일 훅을 비활성화 할 수 있습니다.

TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook); 
+0

+1이 후크를 등록 취소하는 공식 방법을 보여 주려합니다. –

+0

저는 그 사실을 알지 못했지만, 방금 VCL 스타일로 시작했기 때문에 아직 익숙하지 않았습니다. 이후 우리는 타사 Alpha 컨트롤을 사용했지만 델파이 VCL 스타일을 사용하기로 결정했습니다. 고맙습니다. – Nix