// PropertySheetCapture.cpp : implementation file // #include "stdafx.h" #include "resource.h" #include "ScreenGrabber.h" #include "PropertySheetCapture.h" #include "PropertyPageActivation.h" #include "PropertyPageSource.h" #include "PropertyPageDestination.h" #include "PropertyPageImage.h" #include "PropertyPageFile.h" #include "PropertyPagePreferences.h" #include "UTSampleAbout.h" #include "path.h" #include "OXScreenGrab.h" #include "oxbmpfle.h" #include "oxjpgfle.h" #include "oxjpgcom.h" #include "oxjpgdom.h" #include "oxjpgexp.h" // GIF classes available at additional request (due to patent fee) //#include "oxgiffle.h" #include "OXMainRes.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif static CWnd* g_pWndLastForeground; ///////////////////////////////////////////////////////////////////////////// // CPropertySheetCapture dialog // array of control IDs and corresponding help IDs const DWORD CPropertySheetCapture::m_nHelpIDs[] = { 0, 0 }; CPropertySheetCapture::CPropertySheetCapture(UINT nIDCaption, CWnd *pParentWnd, UINT iSelectPage) : COXContextHelpPropertySheet(nIDCaption, pParentWnd, iSelectPage) { IniPropertySheet(); } CPropertySheetCapture::CPropertySheetCapture(LPCTSTR pszCaption, CWnd *pParentWnd, UINT iSelectPage) : COXContextHelpPropertySheet(pszCaption, pParentWnd, iSelectPage) { IniPropertySheet(); } void CPropertySheetCapture::IniPropertySheet() { m_bInitialized=FALSE; pWndTrackingHelper=NULL; m_bIsCapturing=FALSE; m_nTimerCaptureDelay=0; m_bGettingRectArea=FALSE; // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); // initialize Taskbar Icon IniTaskbarIcon(); } void CPropertySheetCapture::IniTaskbarIcon() { m_TaskbarIcon.Create(); // When there is only one taskbar icon, you don't need to specify an ID. // The ID is useful only when implementing two (or more) taskbar icons, AND you want // to handle mouse messages from both icons within one message handler (therefore, you // need that ID to tell which icon posted the msg). However, it might be a good idea to // assign an ID, and check the ID in the message handler, especially when you may need // to derive your classes (somebody else may add another taskbar icon). // Note: you don't need to detroy a taskbar icon. It's done in its own destructor. m_TaskbarIcon.m_pPopupOwner = this; // let this dialog handle popup menu's message // Note: m_pPopupOwner is NOT a member of COXTaskbarIcon. m_TaskbarIcon.SetIcon(IDR_MAINFRAME); m_TaskbarIcon.SetTooltipText(AFX_IDS_APP_TITLE); m_TaskbarIcon.Show(); } BEGIN_MESSAGE_MAP(CPropertySheetCapture, COXContextHelpPropertySheet) //{{AFX_MSG_MAP(CPropertySheetCapture) ON_WM_SYSCOMMAND() ON_BN_CLICKED(IDOK, OnButtonCapture) ON_BN_CLICKED(IDCANCEL, OnButtonClose) ON_WM_TIMER() ON_WM_LBUTTONDOWN() ON_WM_CREATE() ON_WM_DESTROY() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_SIZE() ON_WM_GETMINMAXINFO() //}}AFX_MSG_MAP ON_COMMAND(ID_OPEN, OnOpen) ON_COMMAND(ID_CLOSE, OnButtonClose) ON_COMMAND(ID_ABOUT, OnAppAbout) ON_MESSAGE(WM_HOTKEY,OnHotKey) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CPropertySheetCapture message handlers int CPropertySheetCapture::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (COXContextHelpPropertySheet::OnCreate(lpCreateStruct) == -1) return -1; // TODO: Add your specialized creation code here // Make it resizable ModifyStyle(0,WS_THICKFRAME); // ModifyStyle(0,WS_MAXIMIZEBOX); // create window that we use to show tracking rectangle // while capturing rectangular area pWndTrackingHelper=new CWndTrackingHelper; // make it transparent if(!pWndTrackingHelper->CreateEx(WS_EX_TRANSPARENT|WS_EX_TOOLWINDOW, AfxRegisterWndClass(0), _T(""), WS_POPUP, 0, 0, 0, 0, NULL, NULL)) { TRACE0("Warning: unable to create tracking helper window!\n"); AfxThrowResourceException(); } ASSERT(pWndTrackingHelper->m_hWnd != NULL); return 0; } void CPropertySheetCapture::OnDestroy() { COXContextHelpPropertySheet::OnDestroy(); // TODO: Add your message handler code here if(pWndTrackingHelper!=NULL) { // delete helper window pWndTrackingHelper->DestroyWindow(); delete pWndTrackingHelper; pWndTrackingHelper=NULL; } } BOOL CPropertySheetCapture::OnInitDialog() { COXContextHelpPropertySheet::OnInitDialog(); CMenu* pSysMenu = GetSystemMenu(FALSE); // Remove standard Restore, Maximize & Minimize items out of system menu. if (pSysMenu != NULL) { pSysMenu->RemoveMenu(SC_RESTORE,MF_BYCOMMAND); pSysMenu->RemoveMenu(SC_MINIMIZE,MF_BYCOMMAND); pSysMenu->RemoveMenu(SC_MAXIMIZE,MF_BYCOMMAND); } // Add "Minimize" menu item to system menu. // IDM_MINIMIZE must be in the system command range. ASSERT((IDM_MINIMIZE & 0xFFF0) == IDM_MINIMIZE); ASSERT(IDM_MINIMIZE < 0xF000); if (pSysMenu != NULL) { CString strMinimizeMenu(_T("Mi&nimize")); if (!strMinimizeMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_STRING, IDM_MINIMIZE, strMinimizeMenu); } } // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here m_LayoutManager.Attach(this); m_LayoutManager.SetConstraint(IDOK, OX_LMS_RIGHT, OX_LMT_OPPOSITE, -6, IDCANCEL); m_LayoutManager.SetConstraint(IDOK, OX_LMS_BOTTOM, OX_LMT_SAME, -5); m_LayoutManager.SetConstraint(IDCANCEL, OX_LMS_RIGHT, OX_LMT_OPPOSITE, -6, IDHELP); m_LayoutManager.SetConstraint(IDCANCEL, OX_LMS_BOTTOM, OX_LMT_SAME, -5); m_LayoutManager.SetConstraint(IDHELP, OX_LMS_RIGHT, OX_LMT_SAME, -4); m_LayoutManager.SetConstraint(IDHELP, OX_LMS_BOTTOM, OX_LMT_SAME, -5); m_LayoutManager.SetConstraint(GetTabControl()->GetDlgCtrlID(), OX_LMS_LEFT, OX_LMT_SAME, 4); m_LayoutManager.SetConstraint(GetTabControl()->GetDlgCtrlID(), OX_LMS_RIGHT, OX_LMT_SAME, -4); m_LayoutManager.SetConstraint(GetTabControl()->GetDlgCtrlID(), OX_LMS_BOTTOM, OX_LMT_OPPOSITE, -7, IDOK); m_LayoutManager.SetConstraint(GetTabControl()->GetDlgCtrlID(), OX_LMS_TOP, OX_LMT_SAME, 7); // Draw the layout with the new constraints // This is necessary when constraints are implemented and the window must be refreshed CRect rect; GetWindowRect(&rect); GetTabControl()->AdjustRect(FALSE,&rect); m_LayoutManager.OnSize(rect.Width(),rect.Height()); // rename standard OK button CWnd* pButtonOK=GetDlgItem(IDOK); pButtonOK->SetWindowText(_T("Capture")); // rename standard Cancel button CWnd* pButtonCancel=GetDlgItem(IDCANCEL); pButtonCancel->SetWindowText(_T("Close")); m_bInitialized=TRUE; GetTabControl()->GetWindowRect(&m_rectPage); GetTabControl()->AdjustRect(FALSE,&m_rectPage); ScreenToClient(&m_rectPage); GetActivePage()->MoveWindow(&m_rectPage); return TRUE; } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CPropertySheetCapture::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { COXContextHelpPropertySheet::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CPropertySheetCapture::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CPropertySheetCapture::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { OnAppAbout(); } else { if ((nID & 0xFFF0) == IDM_MINIMIZE) { OnMinimize(); } else { COXContextHelpPropertySheet::OnSysCommand(nID, lParam); } } } LRESULT CPropertySheetCapture::OnHotKey(WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); if((int)wParam!=ID_HOTKEY || m_nTimerCaptureDelay!=0 || m_bIsCapturing) return 0; // user pressed hot key CPropertyPageActivation* pActivation=(CPropertyPageActivation*)GetPage(0); if(pActivation->m_bInitialDelay) { // if needed set initial delay m_nTimerCaptureDelay=SetTimer(ID_TIMER_CAPTURE_DELAY, (DWORD)pActivation->m_nInitialDelay*(DWORD)1000,NULL); if(m_nTimerCaptureDelay==0) { AfxMessageBox(_T("Cannot create timer to set initial delay!"), MB_OK|MB_ICONEXCLAMATION); } } else { // start capturing DoCapture(); } return 0; } void CPropertySheetCapture::OnLButtonDown(UINT nFlags, CPoint point) { UNREFERENCED_PARAMETER(nFlags); if(m_bGettingRectArea) { // if capture area is rectangle ReleaseCapture(); m_bGettingRectArea=FALSE; COXScreenGrabber ScreenGrabber; ScreenGrabber.GrabTracker(this,point,pWndTrackingHelper); // remove helper window from screen RemoveTrackingHelper(); // try to stream captured image to the destination(s) StreamCapture(ScreenGrabber.GetGrabDIB()); } } void CPropertySheetCapture::OnButtonCapture() { // refresh all vars PressButton(PSBTN_APPLYNOW); // if(!DoRegisterHotKey()) { AfxMessageBox(_T("Cannot register Hot Key!")); } else { // remove property sheet from screen OnMinimize(); } } void CPropertySheetCapture::OnTimer(UINT nIDEvent) { switch(nIDEvent) { case ID_TIMER_CAPTURE_DELAY: { KillTimer(m_nTimerCaptureDelay); m_nTimerCaptureDelay=0; // start capturing DoCapture(); break; } default: break; } } BOOL CPropertySheetCapture::DoRegisterHotKey() { // BOOL bProcessed=FALSE; UINT vk; // define hot key to register CPropertyPageActivation* pActivation=(CPropertyPageActivation*)GetPage(0); if(pActivation->m_sHotKey==_T("F1")) vk=VK_F1; else if(pActivation->m_sHotKey==_T("F2")) vk=VK_F2; else if(pActivation->m_sHotKey==_T("F3")) vk=VK_F3; else if(pActivation->m_sHotKey==_T("F4")) vk=VK_F4; else if(pActivation->m_sHotKey==_T("F5")) vk=VK_F5; else if(pActivation->m_sHotKey==_T("F6")) vk=VK_F6; else if(pActivation->m_sHotKey==_T("F7")) vk=VK_F7; else if(pActivation->m_sHotKey==_T("F8")) vk=VK_F8; else if(pActivation->m_sHotKey==_T("F9")) vk=VK_F9; else if(pActivation->m_sHotKey==_T("F10")) vk=VK_F10; else return FALSE; return RegisterHotKey(GetSafeHwnd(),ID_HOTKEY,0,vk); } BOOL CPropertySheetCapture::AdjustToolTips() { return TRUE; } void CPropertySheetCapture::OnMinimize() { m_TaskbarIcon.SetOwner(NULL); // let taskbar icon do it // This is only one way to hide the dialog window. In real situation, you may // want to try DestroyWindow() to conserve system resource if possible (in this // demo, this dialog is the main window). ShowWindow(SW_HIDE); } void CPropertySheetCapture::OnButtonClose() { // try to cleanup everything if(!CleanupCapture()) { return; } // simulate pressing OK button to save all changes PressButton(PSBTN_OK); } // handling popup menu commands sent by the taskbar icon object void CPropertySheetCapture::OnOpen() { // try to cleanup everything if(!CleanupCapture()) { return; } SetForegroundWindow(); ShowWindow(SW_SHOW); } BOOL CPropertySheetCapture::CleanupCapture() { // if we are capturing image then return unsuccess if(m_bIsCapturing) { return FALSE; } // unregister hot key if we close application // when capturing is started UnregisterHotKey(GetSafeHwnd(),ID_HOTKEY); // if we close while waiting for initial delay then // kill timer if(m_nTimerCaptureDelay!=0) { KillTimer(m_nTimerCaptureDelay); m_nTimerCaptureDelay=0; } // if we close while getting capture rectangular area then // release capture and remove helper window if(m_bGettingRectArea) { ReleaseCapture(); RemoveTrackingHelper(); m_bGettingRectArea=FALSE; } return TRUE; } void CPropertySheetCapture::DoCapture() { m_bIsCapturing=TRUE; // get needed property pages CPropertyPageSource* pSource=(CPropertyPageSource*)GetPage(1); CPropertyPagePreferences* pPreferences=(CPropertyPagePreferences*)GetPage(5); // hide TaskbarIcon if needed if(pPreferences->m_bHideIcon) { m_TaskbarIcon.Hide(); } COXScreenGrabber ScreenGrabber; switch(pSource->m_nRadioCapturedArea) { case 0: { ScreenGrabber.GrabFullWindow(CWnd::GetActiveWindow()); break; } case 1: { ScreenGrabber.GrabClientWindow(CWnd::GetActiveWindow()); break; } case 2: { ScreenGrabber.GrabFullWindow(CWnd::GetDesktopWindow()); break; } case 3: { m_bGettingRectArea=TRUE; // activate helper window SetTrackingHelper(); SetCapture(); return; } default: break; } // try to stream captured image to the destination(s) StreamCapture(ScreenGrabber.GetGrabDIB()); } void CPropertySheetCapture::StreamCapture(COXDIB* pDIB) { if(pDIB==NULL) { TRACE0("CPropertySheetCapture::StreamCapture - pDIB==NULL"); return; } CSize sizeDIB=pDIB->GetSize(); if(sizeDIB.cx==0 && sizeDIB.cy==0) { TRACE0("CPropertySheetCapture::StreamCapture - pDIB is empty"); return; } // get needed property pages // CPropertyPageActivation* pActivation=(CPropertyPageActivation*)GetPage(0); // CPropertyPageSource* pSource=(CPropertyPageSource*)GetPage(1); CPropertyPageDestination* pDestination=(CPropertyPageDestination*)GetPage(2); CPropertyPageImage* pImage=(CPropertyPageImage*)GetPage(3); CPropertyPageFile* pFile=(CPropertyPageFile*)GetPage(4); CPropertyPagePreferences* pPreferences=(CPropertyPagePreferences*)GetPage(5); // resize image if needed if(pImage->m_bResize) { UINT nHeight,nWidth; nHeight=pImage->m_nHeight; nWidth=pImage->m_nWidth; // take into account aspect ratio if needed if(pImage->m_bMaintainRatio) { nHeight=(UINT)(((long)nWidth*(long)sizeDIB.cy)/ ((long)sizeDIB.cx)); } if(sizeDIB.cx!=(int)nWidth || sizeDIB.cy!=(int)nHeight) { pDIB->ResizeDIB(nWidth,nHeight); } } // copy captured image to clipboard if needed if(pDestination->m_bClipboard) { SaveAsClipboard(pDIB); } // copy captured image to file if needed if(pDestination->m_bFile) { BOOL bSuccess=TRUE; // check if Capture Directory exists COXPathSpec pathSpec; if(!pathSpec.SetDirectory(pFile->m_sCaptureDir)) { AfxMessageBox(_T("Specified Capture Directory is not valid!")); bSuccess=FALSE; } else { CString sFileName; if(pFile->m_bAutomaticNaming) { // check if we are capable of automatically naming Capture File if(!pathSpec.MakeUnique()) { AfxMessageBox(_T("Cannot automatically name file!")); bSuccess=FALSE; } sFileName=pathSpec.GetBaseName(); } else { sFileName=pFile->m_sFileName; } if(bSuccess) { if(pFile->m_sFileType==CString(_T("Windows Bitmap (*.bmp)"))) { sFileName+=CString(".bmp"); } else { if(pFile->m_sFileType==CString(_T("JPEG Bitmap (*.jpg)"))) { sFileName+=CString(".jpg"); } else { if(pFile->m_sFileType==CString(_T("GIF Image (*.gif)"))) { sFileName+=CString(".gif"); } } } // check if we are capable of creating Capture File if(!pathSpec.SetFileName(sFileName)) { AfxMessageBox(_T("Specified Capture Path is not valid"), MB_OK|MB_ICONEXCLAMATION); bSuccess=FALSE; } } } // save captured image to file if(bSuccess) { if(pFile->m_sFileType==CString(_T("Windows Bitmap (*.bmp)"))) { SaveAsBMP(pDIB,pathSpec.GetPath()); } else { if(pFile->m_sFileType==CString(_T("JPEG Bitmap (*.jpg)"))) { SaveAsJPEG(pDIB,pathSpec.GetPath()); } else { if(pFile->m_sFileType==CString(_T("GIF Image (*.gif)"))) { SaveAsGIF(pDIB,pathSpec.GetPath()); } } } } } // restore TaskbarIcon if it was hidden if(pPreferences->m_bHideIcon) { m_TaskbarIcon.Show(); } m_bIsCapturing=FALSE; // notify about end of capture if needed if(pPreferences->m_bNotifyEnd) { AfxMessageBox(_T("The capture has been completed!"), MB_OK|MB_ICONINFORMATION); } } BOOL CPropertySheetCapture::SaveAsClipboard(COXDIB* pDIB) { if(!OpenClipboard()) { AfxMessageBox("Cannot open the Clipboard!"); return FALSE; } // Remove the current Clipboard contents if(!::EmptyClipboard()) { AfxMessageBox("Cannot empty the Clipboard!"); ::CloseClipboard(); return FALSE; } // create a copy of DIB image HDIB hDIB=pDIB->MakeCopy(); // For the appropriate data formats... if(::SetClipboardData(CF_DIB, hDIB)==NULL) { AfxMessageBox( "Unable to set Clipboard data!" ); ::CloseClipboard(); return FALSE; } // ... ::CloseClipboard(); return TRUE; } BOOL CPropertySheetCapture::SaveAsBMP(COXDIB* pDIB, LPCTSTR lpszPathName) { BOOL bSuccess=FALSE; // try to open or create file CFile m_file; TRY { bSuccess=m_file.Open(lpszPathName,CFile::modeCreate|CFile::modeReadWrite); } CATCH(CFileException,e) { TCHAR szCause[255]; CString strFormatted; e->GetErrorMessage(szCause, 255); strFormatted = _T("CPropertySheetCapture::SaveAsBMP:exception: "); strFormatted += szCause; TRACE(strFormatted); } END_CATCH if(!bSuccess) { CString sMessage; sMessage.Format(_T("Cannot open or create %s!"),lpszPathName); AfxMessageBox(sMessage); return FALSE; } CArchive ar(&m_file, CArchive::store); bSuccess=pDIB->Write(ar); ar.Close(); return bSuccess; } BOOL CPropertySheetCapture::SaveAsJPEG(COXDIB* pDIB, LPCTSTR lpszPathName) { BOOL bSuccess=FALSE; BeginWaitCursor(); // mem file for captured image CMemFile m_tmpBMPFile; CArchive ar(&m_tmpBMPFile, CArchive::store); bSuccess=pDIB->Write(ar); ar.Close(); m_tmpBMPFile.SeekToBegin(); // create bitmap file COXBMPFile BMPFile(&m_tmpBMPFile); COXJPEGFile jpgFile(lpszPathName); COXJPEGCompressor JCompr; short nReturn(1); TCHAR ErrorBuffer[SIZE_ERROR_BUF]; TRY { // the only line of code we need to convert bitmap to JPEG nReturn = JCompr.DoCompress(&BMPFile, &jpgFile); if (nReturn == 2) AfxMessageBox(JCompr.GetWarningMessages()); } CATCH(COXJPEGException, e) { e->GetErrorMessage(ErrorBuffer, SIZE_ERROR_BUF); AfxMessageBox(CString("Exception : ") + ErrorBuffer); TRACE((LPCTSTR)ErrorBuffer); } END_CATCH EndWaitCursor(); return nReturn==0 ? TRUE : FALSE; } BOOL CPropertySheetCapture::SaveAsGIF(COXDIB* pDIB, LPCTSTR lpszPathName) { UNREFERENCED_PARAMETER(pDIB); UNREFERENCED_PARAMETER(lpszPathName); return FALSE; } void CPropertySheetCapture::SetTrackingHelper() { // set helper window for purpose of selecting rectangular area to capture LockWindowUpdate(); g_pWndLastForeground=GetForegroundWindow(); if(g_pWndLastForeground==NULL) { g_pWndLastForeground=GetDesktopWindow(); } ::SetCursor(AfxGetApp()->LoadCursor(IDC_OX_HAND_CURSOR)); pWndTrackingHelper->SetWindowPos(&wndTopMost,0,0,::GetSystemMetrics(SM_CXSCREEN), ::GetSystemMetrics(SM_CYSCREEN),SWP_SHOWWINDOW); } void CPropertySheetCapture::RemoveTrackingHelper() { pWndTrackingHelper->SetWindowPos(&wndBottom,0,0,0,0,SWP_HIDEWINDOW); ASSERT(g_pWndLastForeground->m_hWnd != NULL); g_pWndLastForeground->SetForegroundWindow(); UnlockWindowUpdate(); } void CPropertySheetCapture::OnAppAbout() { CUTSampleAboutDlg dlgAbout(IDR_MAINFRAME,ID_DESCRIPTION_FILE); dlgAbout.DoModal(); } void CPropertySheetCapture::OnSize(UINT nType, int cx, int cy) { COXContextHelpPropertySheet::OnSize(nType, cx, cy); // TODO: Add your message handler code here if(m_bInitialized) { m_LayoutManager.OnSize(cx,cy); GetTabControl()->GetWindowRect(&m_rectPage); GetTabControl()->AdjustRect(FALSE,&m_rectPage); ScreenToClient(&m_rectPage); GetActivePage()->MoveWindow(&m_rectPage); } } BOOL CPropertySheetCapture::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { BOOL result=COXContextHelpPropertySheet::OnNotify(wParam, lParam, pResult); if(result) { NMHDR* pnmh = (LPNMHDR) lParam; // the sheet resizes the page whenever it is activated // so we need to resize it to what we want if (TCN_SELCHANGE == pnmh->code) { // user-defined message needs to be posted because page must // be resized after TCN_SELCHANGE has been processed GetActivePage()->MoveWindow(&m_rectPage); } } return result; } void CPropertySheetCapture::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { // TODO: Add your message handler code here and/or call default COXContextHelpPropertySheet::OnGetMinMaxInfo(lpMMI); // lpMMI->ptMaxSize.x=540; // lpMMI->ptMaxSize.y=360; // lpMMI->ptMaxTrackSize.x=540; // lpMMI->ptMaxTrackSize.y=360; lpMMI->ptMinTrackSize.x=300; // lpMMI->ptMinTrackSize.y=240; }