YOU CAN CODE!

 

With The Case Of UCanCode.net  Release The Power OF  Visual C++ !   HomeProducts | PurchaseSupport | Downloads  
Download Evaluation
Pricing & Purchase?
E-XD++Visual C++/ MFC Products
Overview
Features Tour 
Electronic Form Solution
Visualization & HMI Solution
Power system HMI Solution
CAD Drawing and Printing Solution

Bar code labeling Solution
Workflow Solution

Coal industry HMI Solution
Instrumentation Gauge Solution

Report Printing Solution
Graphical modeling Solution
GIS mapping solution

Visio graphics solution
Industrial control SCADA &HMI Solution
BPM business process Solution

Industrial monitoring Solution
Flowchart and diagramming Solution
Organization Diagram Solution

Graphic editor Source Code
UML drawing editor Source Code
Map Diagramming Solution

Architectural Graphic Drawing Solution
Request Evaluation
Purchase
ActiveX COM Products
Overview
Download
Purchase
Technical Support
  General Q & A
Discussion Board
Contact Us

Links

Get Ready to Unleash the Power of UCanCode .NET


UCanCode Software focuses on general application software development. We provide complete solution for developers. No matter you want to develop a simple database workflow application, or an large flow/diagram based system, our product will provide a complete solution for you. Our product had been used by hundreds of top companies around the world!

"100% source code provided! Free you from not daring to use components because of unable to master the key technology of components!"


VC++ Sample:  Screen Capture

 
 

Introduction

There are many screen capture programs available, but I was not happy with most of them. So I made a screen capture program myself. This program will not offer you the facility to take the picture of  drop down menu and this feature is intentionally excluded. If you would like to implement IT yourself; you will find enough information on the internet. Also, it involves another module as a DLL, where I wanted to keep it simple.

Background

The complete application is not only about screen capturing, but other subjects like WTL, STL, and more.

Using the code

There are three classes inside the CMainFrame window: WindowInfo, CBorderWnd, and CClientView.

There are many interesting attributes of Windows, but this program is only interested in three, the title of the window, the application (or module) name, and the thread ID of the application. The application does not use object-oriented/encapsulation guidelines, so everything is public.

First, you need to create an MDI application with the WTL wizard.

The wizard will create the CMainFrame class in the MainForm (header and CPP) files. The following classes are declared inside MainFrm.h:

//
class WindowInfo
{
public:
    WindowInfo(TCHAR* pstrWindowTitle=NULL, 
               TCHAR* pstrModuleName=NULL, DWORD dwPID=0) 
    {
        memset(m_strWindowTitle,0,_MAX_PATH);
        memset(m_strModuleName,0,_MAX_PATH);

        if (pstrWindowTitle != NULL)
            strcpy_s(m_strWindowTitle,pstrWindowTitle);
        if (pstrModuleName != NULL)
            strcpy_s(m_strModuleName,pstrModuleName);
        m_dwPID = dwPID;

    }
    TCHAR m_strWindowTitle[_MAX_PATH];
    TCHAR m_strModuleName[_MAX_PATH];
    DWORD m_dwPID;
}; 
//

The class CBorderWnd is responsible for drawing the border around another window, and only WM_ERASEBKGND is handled.

Collapse
//
class CBorderWnd : public CWindowImpl<CBorderWnd>
{
public:
    BEGIN_MSG_MAP(CBorderWnd)
        MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
    END_MSG_MAP()
      LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, 
              LPARAM lParam, BOOL& bHandled)
    {
        RECT rect;
        GetClientRect(&rect);
        bHandled = TRUE;
        HDC hDC  = (HDC)wParam;
        HPEN hRedPen = ::CreatePen(PS_SOLID, 16, RGB(255,0,0));
        HPEN hOldPen = (HPEN) ::SelectObject(hDC,hRedPen);
        HBRUSH hOldBrush = (HBRUSH) SelectObject(hDC,
                           (HBRUSH)GetStockObject(NULL_BRUSH));
        Rectangle(hDC,rect.left,rect.top,rect.right,rect.bottom);
        ::SelectObject(hDC,hOldPen);
        ::SelectObject(hDC,hOldBrush);
        DeleteObject(hRedPen);
        return 0;
    }
};
//

And CClientView will draw any picture inside the MDI application.

//
class CClientView : public CWindowImpl<CClientView>
{
public:
    HBITMAP m_bmSonyCamera;
    SIZE m_size;

    BEGIN_MSG_MAP(CSlideView)
        MESSAGE_HANDLER(WM_SIZE, OnSize)
        MESSAGE_HANDLER(WM_PAINT, OnPaint)
        MESSAGE_HANDLER(WM_CREATE, OnCreate)
    END_MSG_MAP()
      LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, 
              LPARAM /*lParam*/, BOOL& /*bHandled*/);
    LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, 
            LPARAM /*lParam*/, BOOL& /*bHandled*/);
    LRESULT OnSize(UINT uMsg, WPARAM wParam, 
            LPARAM lParam, BOOL& bHandled);
};
//

When we create a view with a new keyword, WTL will delete that memory location and there will be no memory leak, but still we want to keep track of all the views whenever we create them. For this reason, the vector<CChildFrame*> m_bmList; is included. Before creating a view, we also need to keep information about all Desktop Windows where map<HWND,WindowInfo> m_HanldeList; is used. A static function is also needed for the EnumDesktopWindows function.

static BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam);

This application has an owner draw combo box, and in owner draw code, you can create a font and delete the font after using it, but the best way to handle it is to assign the font to the object (combo box) by:

::SendMessage(m_hWndComboBox,(UINT) WM_SETFONT,(WPARAM) m_hFont,TRUE);

This way, you need to create a font only once and delete it at exit.

As you can see from the picture, the combo box is inside the Toolbar, so the resource file has to be modified. Depending on the size of any object in the Toolbar, many SEPARATORs (8 pixels) are needed. In this case, 32 SEPARATORs were included. Now, make that combo box and set the toolbar as the parent. The resource file has to be modified with the text editor, else the wizard will override your modification and the result might not be desirable.

Collapse
IDR_MAINFRAME TOOLBAR  16, 15
BEGIN
    BUTTON      ID_FILE_NEW
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    SEPARATOR
    BUTTON      ID_REFRESH
    BUTTON      ID_EDIT_COPY
    BUTTON      ID_FILE_SAVE
    SEPARATOR
    BUTTON      ID_APP_ABOUT
END

Inside the CMainFrame::Create function, the combo box and the font are created.

Collapse
HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME, 
                   FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE);

DWORD dwComboStyle = CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | 
                     WS_CHILD | WS_VISIBLE;
dwComboStyle |= CBS_HASSTRINGS | CBS_OWNERDRAWFIXED;
m_hWndComboBox = ::CreateWindowEx(0,"COMBOBOX", NULL, dwComboStyle, 
                 20,0,400,20,hWndToolBar, (HMENU) COMBOBOX_ID, 
                 _Module.m_hInst, NULL);

m_hFont = CreateFont(-14,                 // nHeight
               0,                         // nWidth
               0,                         // nEscapement
               0,                         // nOrientation
               FW_BOLD,                   // nWeight
               FALSE,                     // bItalic
               FALSE,                     // bUnderline
               0,                         // cStrikeOut
               ANSI_CHARSET,              // nCharSet
               OUT_DEFAULT_PRECIS,        // nOutPrecision
               CLIP_DEFAULT_PRECIS,       // nClipPrecision
               DEFAULT_QUALITY,           // nQuality
               DEFAULT_PITCH | FF_SWISS,  // PitchAndFamily
               "Comic Sans MS"); 

::SendMessage(m_hWndComboBox,(UINT) WM_SETFONT,(WPARAM) m_hFont,TRUE);

Inside CMainFrame, WM_SIZE is also implemented, so when the size is changed, the CClientView will change its size, and place the picture in the middle of the client area. Here, PostMessage is used, so the client always has to find out the area of the parent window. The SendMessage will not work.

You will also find a refresh or window indicator button. When you press it, it will put a border around the window of the selected item in the combo box. Actually, it is a popup window where the middle of the window is painted with a NULL brush. This is the way I implemented it, or you can use the DrawAnimatedRects function.

Collapse
LRESULT CMainFrame::OnRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, 
                              HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
    HWND hSavedWnd = BringToTheTop();
    Sleep(5);
    RECT rectFrom;
    ::GetWindowRect(hSavedWnd,&rectFrom);
//  RECT rectTo;
//    ::SetRect(&rectTo,rectFrom.left,rectFrom.top,
//            rectFrom.right,rectFrom.bottom);
//    ::InflateRect(&rectTo,-100,-100);
//    ::DrawAnimatedRects(hSavedWnd, IDANI_CAPTION, 
//                      &rectFrom, &rectTo);

    WindowInfo WInfo = m_HanldeList[hSavedWnd];

    if (_stricmp(_T("Program Manager"),WInfo.m_strWindowTitle))
       ::InflateRect(&rectFrom,8,8);

    int nWidth  = rectFrom.right - rectFrom.left;
    int nHeight = rectFrom.bottom - rectFrom.top;

    ::SetWindowPos(m_BackGround,HWND_BOTTOM,rectFrom.left,
                   rectFrom.top,nWidth,nHeight,SWP_SHOWWINDOW);
    Sleep(2000);
    ::SetWindowPos(m_BackGround,HWND_TOP,rectFrom.left,
                   rectFrom.top,nWidth,nHeight,SWP_HIDEWINDOW);
    return 0;
}
The heart of the program is adding enum windows to the list box. We are only interested in the application windows (not child windows, or invisible windows, or zero size windows).

 

Collapse
void CMainFrame::AddToTheList(HWND hWnd)
{
    TCHAR tchCurrentSelected[_MAX_PATH];
    TCHAR tchBuffer[_MAX_PATH];
    TCHAR tchClassName[_MAX_PATH];
    TCHAR tchModuleName[_MAX_PATH];
    HANDLE hProcess;

    ::GetWindowText(hWnd,tchCurrentSelected,_MAX_PATH);

    int nCount = 0;
    bool bChanged = false;
    do
    {
        bChanged = false;
        nCount = SendMessage(m_hWndComboBox, 
                (UINT) CB_GETCOUNT,0,NULL);
        for (int i = 0; i < nCount; i++) 
        {
            HWND hSavedWnd = (HWND) SendMessage(m_hWndComboBox, 
                             (UINT) CB_GETITEMDATA,i,NULL);
            if (::IsWindow(hSavedWnd) == FALSE)
            {
               ::SendMessage(m_hWndComboBox,CB_DELETESTRING,i,0);
                bChanged = true;
                map<HWND,WindowInfo>::iterator Pos = 
                             m_HanldeList.find(hSavedWnd);
                if (Pos != m_HanldeList.end())
                    m_HanldeList.erase(Pos);
                int nSel = ::SendMessage(m_hWndComboBox,CB_FINDSTRING,
                           -1,(LPARAM) (LPCTSTR)tchCurrentSelected);
                
                int NewSel = (nSel == CB_ERR) ? 0 : nSel;
                SendMessage(m_hWndComboBox, 
                           (UINT) CB_SETCURSEL,NewSel,NULL);
                break;
            }
        }
    }while (bChanged);

    if (::IsWindow(hWnd) == FALSE || ::IsWindowVisible(hWnd) 
        == FALSE || ::GetParent(hWnd) || hWnd == m_hWnd)
        return;
    
    ::GetWindowText(hWnd,tchBuffer,_MAX_PATH);
    if (strlen(tchBuffer) == 0)
        return;

    int nResult = ::SendMessage(m_hWndComboBox,CB_FINDSTRING,
                  -1,(LPARAM) (LPCTSTR)tchBuffer);
    if (nResult != CB_ERR)
    {
        for (int i = 0; i < nCount; i++)
        {
              HWND hSavedWnd = (HWND) SendMessage(m_hWndComboBox, 
                               (UINT) CB_GETITEMDATA,i,NULL);
            if (hSavedWnd == hWnd)
               return;
        }
    }
    ::GetClassName(hWnd,tchClassName,_MAX_PATH);
    RECT rect;
    ::GetWindowRect(hWnd,&rect);
    // get pid
    DWORD dwPID;
    GetWindowThreadProcessId(hWnd, &dwPID);
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | 
               PROCESS_VM_READ, false, dwPID);
    GetModuleFileNameEx(hProcess, NULL, tchModuleName, _MAX_PATH);
    CloseHandle(hProcess);

    BOOL bDoNoAccept = ::IsWindow(hWnd) == FALSE || 
         ::IsWindowVisible(hWnd) == FALSE || 
         ::GetParent(hWnd) || hWnd == m_hWnd;
        
    if (!bDoNoAccept)
    {
        map<HWND,WindowInfo>::iterator it = 
                            m_HanldeList.find(hWnd);
        bool bHidden = (rect.left == rect.right || 
                        rect.top == rect.bottom);
        if (it == m_HanldeList.end() && bHidden == false)
        {
            m_HanldeList.insert(std::make_pair(hWnd,
                     WindowInfo(tchBuffer,tchModuleName,dwPID)));
            nResult = ::SendMessage(m_hWndComboBox,CB_ADDSTRING,
                      0,(LPARAM) (LPCTSTR)tchBuffer);
            if (nResult != CB_ERR)
                ::SendMessage(m_hWndComboBox,CB_SETITEMDATA,
                              nResult,(LPARAM) (HWND)hWnd);
     
            nCount = SendMessage(m_hWndComboBox, (UINT) CB_GETCOUNT,0,NULL);
            int CurSel = SendMessage(m_hWndComboBox, 
                        (UINT) CB_GETCURSEL,0,NULL);
            if (nCount && CurSel == -1)
                SendMessage(m_hWndComboBox, (UINT) CB_SETCURSEL,0,NULL);
        }
    }
}

As you can see, first, we find the application windows, and then we find its process to get its icon so we could display it inside the combo box.

I hope everyone will enjoy this program.

 

 

Copyright ?1998-2022 UCanCode.Net Software , all rights reserved.
Other product and company names herein may be the trademarks of their respective owners.

Please direct your questions or comments to webmaster@ucancode.net