2009-12-14 4 views
2

Windows를 랩핑하기 위해 (관리되지 않는) C++ 클래스를 작성하고 있습니다. PropertySheet. 기본적으로,이 같은 일이 :와, 모달, 나는 그것을 보여줄 수PropertySheet 배치; 콜백을 처리하는 방법?

PropSheet::PropSheet(/* parameters */) { 
    d_header.dwSize = sizeof(PROPSHEETHEADER); 
    d_header.dwFlags = PSH_USECALLBACK; 
    // ... 
    d_header.pfnCallback = &propSheetProc; 
    // ... 
} 

후 :

INT_PTR PropSheet::show() { 
    return PropertySheet(&d_header); 
} 

지금 문제가

class PropSheet { 
    PROPSHEETHEADER d_header; 
    public: 
     PropSheet(/* parameters */); 
     INT_PTR show(); 
    private: 
     static int CALLBACK *propSheetProc(HWND hwnd, UINT msg, LPARAM lParam); 
}; 

생성자는 단지 d_header 멤버를 초기화 콜백은 정적이므로 래퍼 클래스에 액세스 할 수 없습니다. 정상적인 창일 경우 PropSheetProc 대신 WindowProc이 표시되고 cbWndExtraWNDCLASS에 사용하여 창에 추가 데이터를 첨부 할 수 있습니다. 여기에서 this article처럼 포인터를 래퍼에 다시 저장할 수 있습니다. 그러나 속성 시트는이 기능을 제공하지 않습니다.

또한 속성 시트가 ​​모달로 표시되기 때문에 콜백 또는 시트의 윈도우 프로 시저 중 하나를 통해 코드가 실행되는 경우를 제외하고는 실제 윈도우의 생성과 삭제 사이에 아무 코드도 실행할 수 없습니다.

필자가 지금까지 해왔 던 최상의 솔루션은 속성 시트를 표시하기 전에 전역 변수 내에서 래퍼 클래스에 대한 포인터를 저장하는 것입니다. 그러나 이것은 한 번에 하나의 속성 시트 만 보여줄 것이라고 가정하고 어쨌든 꽤 추합니다.

이 문제를 해결하는 방법에 대해 더 잘 알고있는 사람이 있습니까? 당신은 속성 시트의 모달을 보이고있다으로

답변

1

, 당신은 PropSheetProc()hwndDlg 매개 변수에 ::GetParent()를 사용하여, 인스턴스에 매핑 속성 시트의 부모 창 (즉, 핸들)를 사용할 수 있어야합니다.

+0

아아, 부모가 없습니다. 또한 부모가 여러 속성 시트를 생성 한 경우에도 동일한 문제가 발생합니다.(희귀하다, 나도 알지만, 일어날 수있다.) – Thomas

+0

아니면'PropSheet * '를'HWND'에 던지라고 제안하고 있는가? 'HWND'에 접근하려고하면 윈도우의 폭발이 일어나지 않을까? – Thomas

+0

여기에 오해가 있습니까? 'PROPSHEETHEADER' (즉,'hwndParent')에 부모 윈도우를 설정 (또는 설정해야합니다)합니다. 'PropSheetProc()'에서 당신은'GetParent()'를 호출 할 수있는 첫 번째 매개 변수로서 대화 상자의 핸들을 얻습니다. –

0

사용자 정의 컨텍스트 매개 변수없이 콜백을 사용하는 또 다른 Win32 API입니다. 그것은 슬프게도 유일한 것이 아닙니다. 예 : CreateWindow는 좋지 않습니다 (사용자 정의 컨텍스트를 제공하지만 처음 몇 개의 창 메시지에서는 해당 컨텍스트를 사용할 수 없습니다). SetWindowsHookEx는 더욱 심각합니다 (컨텍스트가 전혀 없습니다).

범용이고 효과적인 유일한 "솔루션"은 'this'포인터가 하드 코드 된 실행 가능한 코드의 작은 조각을 방출하는 것입니다. 이 같은 것 : http://episteme.arstechnica.com/eve/forums/a/tpc/f/6330927813/m/848000817831?r=848000817831#848000817831

끔찍한 일입니다.

+0

CreateWindow()에는 새 창에 사용자 정의 값을 전달할 수있는 lParam 매개 변수가 있습니다. 이 값은 WM_CREATE 메시지의 CREATESTRUCT 구조에서 사용할 수 있습니다. 그런 다음 나중에 SetWindowLong (GWL_USERDATA) 또는 SetProp()과 같은 HWND로 복사하여 나중에 메시지에 사용할 수 있습니다. –

+0

WM_CREATE가 첫 번째 메시지 인 경우 환상적입니다. 그렇지 않습니다. – DrPizza

+0

와우, 그건 내가 결코 생각하지 못한 해킹이다. 그러나 나는 그 길을 감히하지 않을 것이다. – Thomas

0

PROPSHEETPAGE 구조체에는 콜백에 사용할 수있는 lParam 필드가 있습니다. PROPSHEETHEADER에서 PSH_PROPSHEETPAGE 플래그를 포함하여 페이지를 설명하는 PROPSHEETPAGE 항목의 배열을 전달하거나, 미리 할당 된 HPROPSHEETPAGE 핸들 배열 대신 CreatePropertySheetPage()를 사용하여 PROPSHEETPAGE를 사용하는 것을 의미하는 플래그를 생략 할 수 있습니다.

+0

'PropSheetProc()'에 대한 문서에 따르면,'lParam'은 0을 포함합니다. 'PSCB_BUTTONPRESSED'. –

+1

예, 개별 페이지의 창 프로 시저는 문제가되지 않습니다. 내 두통을 일으키는 전체 속성 시트에 대한 콜백입니다. – Thomas

+0

개별 페이지 콜백으로 처리 할 수없는 시트 콜백에서 수행해야하는 작업은 무엇입니까? –

0

당신은 이미 "실제 창을 만들고 파괴하는 사이에 아무 코드도 실행할 수 없다"고 인정했습니다. 그것은 글로벌 변수가 끔찍한 해킹되지 않을 것 같습니다.

0

나는 다른 옵션을 찾았습니다 : SetProp을 사용하여 포인터를 래퍼에 저장하는 속성을 추가하십시오. 속성 시트 콜백에서 SetProp을 호출하려면 전역 변수 만 필요합니다.