C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 팁&트릭
C++Builder Programming Tip&Tricks
[907] [VCL] BDS2005 미만에서 메인폼을 작업표시줄에 나타나게..
장성호 [nasilso] 9083 읽음    2009-07-24 14:47
2005미만 즉 CBuilder6이나 Delphi7 등에서
메인폼을 작업표시줄에 나타나게 하는 방법을 소개합니다.

뭔말인지 잘 이해가 안가시는 분들을 위해...

[VCL 어플리케이션의 메인윈도우 핸들은?]

   BDS2005 이상 버젼에서는 설정에 따라서 다르지만
   기본적으로 VCL(Delphi , CBuilder)에서 메인윈도우는 MainForm->Handle이 아닙니다.
   
   Application->Handle이 VCL 어플리케이션의 메인윈도우핸들 입니다.

    확인하는 쉬운 방법은 작업표시줄에서 어플리케이션 버튼에서 마우스 우클릭하여
    System메뉴를 띄워보세요
    보통 System메뉴는   (이전크기,이동,최대화,최소화,닫기) 이렇게 여섯가지 입니다.
    그런데 메인폼의 캡션에서 메뉴를 띄우면  6개의 메뉴가 나오지만
    작업표시줄에서 메뉴를 띄우면 (이전크기,최소화,닫기) 이렇게 3가지만 나옵니다.

    왜냐하면 Application->Handle 윈도우를 CreateWindow한후에
    MAXIMIZE , SIZE , MOVE 세개의 시스템 메뉴를 삭제하기때문이죠

//TApplication 클래스의 CreateHandle 메소드 코드입니다.
procedure TApplication.CreateHandle;
var
  TempClass: TWndClass;
  SysMenu: HMenu;
begin
      //생략..
     SysMenu := GetSystemMenu(FHandle, False);
    DeleteMenu(SysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
    DeleteMenu(SysMenu, SC_SIZE, MF_BYCOMMAND);
    if NewStyleControls then DeleteMenu(SysMenu, SC_MOVE, MF_BYCOMMAND);
  end;

end;


[Application->MainForm은 어떻게 결정되나?]
  
  Application->MainForm은 프로그램에서 Form을 생성하는 순서에 따라
  Form1이 될수도 있구 Form2도 될수 있습니다.

  일반적으로 먼저 생성되는 폼이 Application->MainForm이 되지만
  좀더 정확하게 표현하면   Application->CreateForm 메소드를 통해
  생성되는 첫번째 폼이  Application->MainForm 이 됩니다.
 
  procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);
var
  Instance: TComponent;
begin
  Instance := TComponent(InstanceClass.NewInstance);
  TComponent(Reference) := Instance;
  try
    Instance.Create(Self);
  except
    TComponent(Reference) := nil;
    raise;
  end;
  //여기서 MainForm이 결정됨 
  if (FMainForm = nil) and (Instance is TForm) then
  begin
    TForm(Instance).HandleNeeded;
    FMainForm := TForm(Instance);
  end;
end; 
 
  

[Application->MainForm과 Application->Hanlde은 무슨 관계?]
   대부분의 경우 VCL로 어플리케이션 개발할때
   Application->Hanlde이 메인윈도우핸들이라는것을 인식하지 못합니다.
  
  왜냐하면
  Application->MainForm에서 발생하는 System-Message중 일부를  Application->Hadle 로 보내구요
  작업표시줄의 Application->Handle의 버튼에서 발생하는 System-Message중 일부를
   Application->MainForm->Handle로 보내기때문입니다.
  ...


[Application->MainForm과 Application->Hanlde의 연결고리 끊기]  
   여기가 가장 중요한데요
  
   다음과 같이 Application->Handle을 hide시키면
   ShowWindow(Application->Handle,SW_HIDE);

    Application->Handle에서 발생하는 system-message를 필터링 하는 기능은
    별로 신경쓰지 않아도 될것입니다.

    하지만  Application->MainForm->Handle에서 발생하는 system-message(WM_SYSCOMMAND)는
    Application->Handle의 WindowProc로 가지 않도록 필터링 해줘야 합니다.


  아래는 TCustomForm의  WM_SYSCOMMAND 메세지에 대한 처리 코드 입니다.

    
procedure TCustomForm.WMSysCommand(var Message: TWMSysCommand);
begin
  with Message do
  begin
    if (CmdType and $FFF0 = SC_MINIMIZE) and (Application.MainForm = Self) then
      Application.WndProc(TMessage(Message))   //여기가 중요
    else if (CmdType and $FFF0 <> SC_MOVE) or (csDesigning in ComponentState) or
      (Align = alNone) or (WindowState = wsMinimized) then
      inherited;
    if ((CmdType and $FFF0 = SC_MINIMIZE) or (CmdType and $FFF0 = SC_RESTORE)) and
      not (csDesigning in ComponentState) and (Align <> alNone) then
      RequestAlign;
  end;
end;

    
   위 코드를 보면   WM_SYSCOMMAND  에서
   CommandType즉 WParam이 SC_MINIMIZE 이구 현재 폼이 Application->MainForm이면
   해당 Application.WndProc 로 보내서 처리하도록 하고 있습니다.
  
코드
  다음과 같이 코딩하면 메인폼의  minimize command가 Application->Handle 의 WindowProc로 가는것을
   막을수 있습니다.

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::CreateParams(Controls::TCreateParams &Params)
{
    TCustomForm::CreateParams(Params);
     //메임폼을 작업표시줄에 표시
     //Form1의 Wndparent를 Gesktopwindow로 설정 
    Params.WndParent=0;   
}
//---------------------------------------------------------------------------
//위와같이 하면 작업표시줄의 메뉴가 6개 모두 나타남

void __fastcall TForm1::WndProc(TMessage &Msg)
{
    if(Msg.Msg==WM_SYSCOMMAND && Msg.WParam==SC_MINIMIZE)
    {
        //Form1의minimize 시스템 메세지를 필터링 
        this->WindowState=wsMinimized;
        return;
    }

    TCustomForm::WndProc(Msg);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
    //Form1이 Show될때 Application->Handle을 hide시킴 
    ShowWindow(Application->Handle,SW_HIDE);
}
//---------------------------------------------------------------------------
//Application->Handle을 Hide시키지 않으면
// 작업표시줄에 버튼이 두개 나타납니다.



앗참
2005이상에서는
WinMain에서  다음과 같이 코딩한후에
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    //
    Application->MainFormOnTaskBar=true;
    SetApplicationMainFormOnTaskBar(Application, true);
    Application->CreateForm(__classid(TF_Main), &F_Main);
 ///

}


그럼..

+ -

관련 글 리스트
907 [VCL] BDS2005 미만에서 메인폼을 작업표시줄에 나타나게.. 장성호 9083 2009/07/24
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.