zoukankan      html  css  js  c++  java
  • 模拟window桌面实现

    正在开发中的游戏有个全屏功能--可以在window桌面背景上运行,就像一些视频播放器在桌面背景上播放一样的,花了个上午整了个Demo放出来留个纪念。

    实现功能:显示图标,双击图标执行相应的程序,右击图标弹出该图标对应得菜单,点击非图标区则弹出桌面菜单。需要完整工程可以点此下载:DesktopWindow.rar。程序效果图如下:

     在这个程序里,定义了一个XShellItem的数据结构,保持桌面图标的iten id(ITEMIDLiST),图标以及文字图标。

        struct XShellItem {
            ITEMIDLIST
    *     itemId;

            
    int x;
            
    int y;
            
    int w;
            
    int h;

            
    int nameX;
            
    int nameY;
            
    int nameW;
            
    int nameH;

            BOOL hit;

            CStringW name;
            Bitmap
    *     icon;
            Bitmap
    *     nameIcon;

            XShellItem()
            :
            itemId(NULL),
            x(
    0),
            y(
    0),
            w(
    0),
            h(
    0),
            nameX(
    0),
            nameY(
    0),
            nameW(
    0),
            nameH(
    0),
            name(L
    ""),
            hit(FALSE),
            icon(NULL),
            nameIcon(NULL) 
    {
            }

            
    ~XShellItem() {
            }

        }
    ;

    然后定义一个数组CAtlArray<XShellItem> itemArray;用来保存所有桌面图标对象,在InitShellFolder()中对它进行初始化:

        // 获取桌面图标的相关数据
        BOOL InitShellFolder()
        
    {
            HRESULT hRslt 
    = SHGetDesktopFolder(&folder);
            
    if (FAILED(hRslt)) {
                
    return FALSE;
            }


            CComPtr
    <IEnumIDList> ids;
            hRslt 
    = folder->EnumObjects(0, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &ids);
            
    if (FAILED(hRslt)) {
                
    return FALSE;
            }


            CAtlList
    <XShellItem> items;
            
    for (;;) {
                ITEMIDLIST
    *     id = 0;
                ULONG cIds 
    = 0;

                hRslt 
    = ids->Next(1&id, &cIds);
                
    if (hRslt != S_OK) {
                    
    break;
                }


                CStringW name;
                STRRET str 
    = 0};
                hRslt 
    = folder->GetDisplayNameOf(id, SHGDN_NORMAL | SHGDN_INFOLDER, &str);
                
    if (SUCCEEDED(hRslt)) {
                    LPWSTR pname 
    = 0;
                    StrRetToStrW(
    &str, id, &pname);
                    name 
    = pname;
                    CoTaskMemFree(pname);
                }


                XShellItem item;

                item.itemId 
    = id;
                item.name 
    = name;
                items.AddTail(item);
            }


            SIZE_T iItem 
    = 0;
            SIZE_T cItems 
    = items.GetCount();

            itemArray.SetCount(cItems);

            POSITION pos 
    = items.GetHeadPosition();
            
    while (pos != 0{
                XShellItem
    &     si = items.GetNext(pos);
                itemArray[iItem] 
    = si;
                iItem
    ++;
            }


            HDC hDC 
    = CreateCompatibleDC(0);

            Graphics g(hDC);
            g.Clear(Color(
    0000));

            ICONMETRICS im 
    = 0};
            im.cbSize 
    = sizeof(im);
            SystemParametersInfo(SPI_GETICONMETRICS, 
    sizeof(im), &im, 0);

            SolidBrush br_t(Color(
    255255255));
            Font font_i(hDC, 
    &(im.lfFont));
            
    float fcy = font_i.GetHeight(&g) * 2 + 2;
            DeleteDC(hDC);

            Gdiplus::StringFormat sf(Gdiplus::StringFormat::GenericTypographic());
            sf.SetAlignment(Gdiplus::StringAlignmentCenter);
            sf.SetTrimming(Gdiplus::StringTrimmingEllipsisWord);

            iconSpacingWidth 
    = im.iHorzSpacing + OFFSET_WIDTH;
            iconSpacingHeight 
    = im.iVertSpacing + OFFSET_HEIGHT;

            
    int iconWidth = GetSystemMetrics(SM_CXICON);
            
    int iconHeight = GetSystemMetrics(SM_CYICON);

            
    for (SIZE_T i = 0; i < cItems; i++{
                XShellItem
    &     item = itemArray[i];

                
    // SHGetFileInfo
                HICON hIcon = 0;
                HIMAGELIST hImgList;
                SHFILEINFO stSHFileInfo;
                CImageList cImgList;

                
    // 获取图标
                hImgList = (HIMAGELIST)::SHGetFileInfo(
                        (LPCWSTR) item.itemId,
                        
    0,
                        
    &stSHFileInfo,
                        
    sizeof(SHFILEINFO),
                        SHGFI_PIDL 
    | SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SYSICONINDEX);

                
    // DIBSection 8bit
                BITMAPINFO bmi;
                BITMAPINFOHEADER
    &  bmih = bmi.bmiHeader;
                bmih.biSize 
    = sizeof(bmih);
                bmih.biWidth 
    = ICON_WIDTH;
                bmih.biHeight 
    = -ICON_HEIGHT;    // BMP反转
                bmih.biPlanes = 1;
                bmih.biBitCount 
    = 32;
                bmih.biCompression 
    = BI_RGB;
                bmih.biSizeImage 
    = 0;
                bmih.biXPelsPerMeter 
    = 0;
                bmih.biYPelsPerMeter 
    = 0;
                bmih.biClrUsed 
    = 0;
                bmih.biClrImportant 
    = 0;

                HDC memDC 
    = CreateCompatibleDC(0);
                
    void*  pDib = 0;
                HBITMAP hBmp 
    = CreateDIBSection(memDC, &bmi, DIB_RGB_COLORS, &pDib, 00);
                GdiFlush();

                HGDIOBJ old 
    = SelectObject(memDC, hBmp);

                
    // ImageList_Draw WindowsXP
                ImageList_SetBkColor(hImgList, 0x0);
                ImageList_Draw(hImgList, stSHFileInfo.iIcon, memDC, 
    00, ILD_NORMAL);
                SelectObject(memDC, old);
                DeleteDC(memDC);

                cImgList.Attach(hImgList);
                hIcon 
    = cImgList.ExtractIcon(stSHFileInfo.iIcon);
                cImgList.Detach();

                
    if (hIcon != 0{

                    
    // Bitmap::FromHICON 0~255
                    item.icon = Bitmap::FromHICON(hIcon);
                    item.w 
    = iconWidth;
                    item.h 
    = iconHeight;

                    Gdiplus::RectF rc(
    float(2), float(2), float(iconSpacingWidth - 4), fcy);

                    Gdiplus::Bitmap 
    * nameIcon = new Bitmap(NAME_WIDTH, NAME_HEIGHT, &g);
                    Gdiplus::Graphics 
    * g2 = Gdiplus::Graphics::FromImage(nameIcon);
                    g2
    ->Clear(Gdiplus::Color(Gdiplus::ARGB(0)));

                    g2
    ->DrawString(item.name, item.name.GetLength(), &font_i, rc, &sf, &br_t);

                    item.nameIcon 
    = nameIcon;
                    item.nameW 
    = NAME_WIDTH;
                    item.nameH 
    = NAME_HEIGHT;

                    delete g2;
                }


                DestroyIcon(hIcon);
                DeleteObject(hBmp);
                DestroyIcon(stSHFileInfo.hIcon);
            }


            
    return TRUE;
        }

    注意这里面并没有设置图标对象的位置,因为当窗口改变大小的时候,相应地也要调整图标的描绘位置,所以图标位置是在SetShellItemPosition()中动态调整的.

        // 根据窗口大小设置图标位置
        void SetShellItemPosition()
        
    {
            
    int iconWidth = GetSystemMetrics(SM_CXICON);
            
    int iconHeight = GetSystemMetrics(SM_CYICON);
            
    static const int OFFSET_Y = 20;
            
    int x = 0;
            
    int y = OFFSET_Y;
            SIZE_T cItems 
    = itemArray.GetCount();
            
    for (SIZE_T i = 0; i < cItems; i++{
                XShellItem
    &     item = itemArray[i];
                
    if (item.icon) {
                    item.x 
    = x + (iconSpacingWidth - iconWidth) / 2;
                    item.y 
    = y;
                }


                
    if (item.nameIcon) {
                    item.nameX 
    = x;
                    item.nameY 
    = y + iconHeight + 2;
                }


                WTL::CRect rect;
                GetClientRect(
    &rect);
                y 
    += iconSpacingHeight;
                
    if (y + iconSpacingHeight >= rect.bottom) {
                    x 
    += iconSpacingWidth;
                    y 
    = OFFSET_Y;
                }

            }

        }

    描绘图标就很简单了,呵呵,不贴了,下面来说说弹出图标菜单,执行图标对应的程序以及弹出桌面菜单。

    执行图标对应的程序,需要以先前保持的图标itemid作为参数,代码如下:

        void RunShellItem(ITEMIDLIST* pIID)
        
    {
            SHELLEXECUTEINFO info;
            info.cbSize 
    = sizeof(SHELLEXECUTEINFO);
            info.fMask 
    = SEE_MASK_INVOKEIDLIST;
            info.hwnd 
    = m_hWnd;
            info.lpVerb 
    = NULL;
            info.lpFile 
    = NULL;
            info.lpParameters 
    = NULL;
            info.lpDirectory 
    = NULL;
            info.nShow 
    = SW_SHOWNORMAL;
            info.hInstApp 
    = NULL;
            info.lpIDList 
    = pIID;
            ShellExecuteEx(
    &info);
        }

    弹出桌面菜单的代码如下:

        // 桌面菜单
        void DesktopMenu()
        
    {
            HWND program 
    = FindWindowEx(00, _T("Progman"), _T("Program Manager"));
            HWND view 
    = FindWindowEx(program, 0, _T("SHELLDLL_DefView"), 0);

            
    //HWND list = FindWindowEx(view, 0, _T("SysListView32"), 0);
            ::SetForegroundWindow(view);

            POINT pt;
            GetCursorPos(
    &pt);

            LPARAM lp 
    = pt.y << 16 | (pt.x - 32);
            ::PostMessage(view, WM_LBUTTONDOWN, 
    0, lp);
            ::PostMessage(view, WM_RBUTTONUP, 
    0, lp);
        }

    弹出图标菜单的代码如下,这里定义了两个全局的IContextMenu对象:
    static IContextMenu2*  g_pIContext2 = NULL;
    static IContextMenu3*  g_pIContext3 = NULL;

    以便在消息回调函数中使用。具体代码如下:

        // 图标菜单
        void RightMenu(ITEMIDLIST* pIID)
        
    {
            HWND hwnd 
    = m_hWnd;

            LPCONTEXTMENU pContextMenu 
    = NULL;
            LPCONTEXTMENU pCtxMenuTemp 
    = NULL;

            g_pIContext2 
    = NULL;
            g_pIContext3 
    = NULL;

            
    int menuType = 0;

            HRESULT hRslt 
    = folder->GetUIObjectOf(
                    hwnd,
                    
    1,
                    (LPCITEMIDLIST
    *&(pIID),
                    IID_IContextMenu,
                    
    0,
                    (
    void**&pCtxMenuTemp);
            
    if (FAILED(hRslt)) {
                
    return;
            }


            POINT pt;
            GetCursorPos(
    &pt);

            
    if (pCtxMenuTemp->QueryInterface(IID_IContextMenu3, (void**&pContextMenu) == NOERROR) {
                menuType 
    = 3;
            }

            
    else if (pCtxMenuTemp->QueryInterface(IID_IContextMenu2, (void**&pContextMenu) == NOERROR) {
                menuType 
    = 2;
            }


            
    if (pContextMenu) {
                pCtxMenuTemp
    ->Release();
            }

            
    else {
                pContextMenu 
    = pCtxMenuTemp;
                menuType 
    = 1;
            }


            
    if (menuType == 0{
                
    return;
            }


            HMENU hMenu 
    = CreatePopupMenu();
            hRslt 
    = pContextMenu->QueryContextMenu(hMenu, 010x7fff, CMF_NORMAL | CMF_EXPLORE);
            
    if (FAILED(hRslt)) {
                
    return;
            }


    #ifndef _WIN64
        
    #pragma warning(disable : 4244 4311)
    #endif

            
    // subclass window
            WNDPROC oldWndProc = NULL;
            
    if (menuType > 1{

                
    // only subclass if it is IID_IContextMenu2 or IID_IContextMenu3
                oldWndProc = (WNDPROC) SetWindowLongPtr(GWL_WNDPROC, (LONG) HookWndProc);
                
    if (menuType == 2{
                    g_pIContext2 
    = (LPCONTEXTMENU2) pContextMenu;
                }

                
    else {
                    g_pIContext3 
    = (LPCONTEXTMENU3) pContextMenu;
                }

            }

            
    else {
                oldWndProc 
    = NULL;
            }


            
    int cmd = ::TrackPopupMenu(
                    hMenu,
                    TPM_LEFTALIGN 
    | TPM_BOTTOMALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON,
                    pt.x,
                    pt.y,
                    
    0,
                    hwnd,
                    
    0);

            
    // unsubclass
            if (oldWndProc) {
                SetWindowLongPtr(GWL_WNDPROC, (LONG) oldWndProc);
            }


    #ifndef _WIN64
        
    #pragma warning(default : 4244 4311)
    #endif
            
    if (cmd != 0{
                CMINVOKECOMMANDINFO ci 
    = 0};
                ci.cbSize 
    = sizeof(CMINVOKECOMMANDINFO);
                ci.hwnd 
    = hwnd;
                ci.lpVerb 
    = (LPCSTR) MAKEINTRESOURCE(cmd - 1);
                ci.nShow 
    = SW_SHOWNORMAL;

                pContextMenu
    ->InvokeCommand(&ci);
            }


            pContextMenu
    ->Release();
            g_pIContext2 
    = NULL;
            g_pIContext3 
    = NULL;
            ::DestroyMenu(hMenu);
        }


        
    static LRESULT CALLBACK HookWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
        
    {
            
    switch (message) {
            
    case WM_MENUCHAR:    // only supported by IContextMenu3
                if (g_pIContext3) {
                    LRESULT lResult 
    = 0;
                    g_pIContext3
    ->HandleMenuMsg2(message, wParam, lParam, &lResult);
                    
    return(lResult);
                }

                
    break;
            
    case WM_DRAWITEM:
            
    case WM_MEASUREITEM:
                
    if (wParam) {
                    
    break;    // if wParam != 0 then the message is not menu-related
                }


            
    case WM_INITMENUPOPUP:
                
    if (g_pIContext2) {
                    g_pIContext2
    ->HandleMenuMsg(message, wParam, lParam);
                }

                
    else {
                    g_pIContext3
    ->HandleMenuMsg(message, wParam, lParam);
                }


                
    return(message == WM_INITMENUPOPUP ? 0 : TRUE);
                
    break;
            
    default:
                
    break;
            }


            
    return ::CallWindowProc((WNDPROC) GetProp(hWnd, TEXT("oldWndProc")), hWnd, message, wParam, lParam);
        }
    jpg改rar 
     
  • 相关阅读:
    第一次博客作业
    C++基础笔记(int转string)
    C++基础笔记(string截取)
    20145222 《信息安全系统设计基础》期中总结
    20145222《信息安全系统设计基础》Linux常用命令汇总
    20145222《信息安全系统设计基础》第七周学习总结(1)
    《Markdown 一些基本语法》
    20145222《信息安全系统设计基础》我的第1-6周考试错题汇总
    20145222《信息安全系统设计基础》第六周学习总结(2)
    20145222《信息安全系统设计基础》第六周学习总结(1)
  • 原文地址:https://www.cnblogs.com/kuangke/p/6626837.html
Copyright © 2011-2022 走看看