Ignore:
Timestamp:
Aug 29, 2009, 7:55:19 AM (15 years ago)
Author:
イグトランス (egtra)
Message:

Windows 7タスクバーへの対応を実装。
(#245)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/ab5.0/abdev/abdev/src/MainFrame.cpp

    r749 r772  
    1010void CreateProcessWithStdHandle( const std::string &appPath, const std::string &cmdLine, bool isShowWindow = true )
    1111{
    12     std::string argsStr = "\"" + appPath + "\" " + cmdLine;
     12    std::string argsStr = '\"' + appPath + "\" " + cmdLine;
    1313    STARTUPINFO si;
    1414    PROCESS_INFORMATION pi;
     
    2121    si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
    2222   
    23     char args[8192];
    24     lstrcpy( args, argsStr.c_str() );
    25 
    26     CreateProcess( NULL, args, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi );
     23    std::vector<char> args( argsStr.c_str(), argsStr.c_str() + argsStr.size() + 1 );
     24
     25    CreateProcess( NULL, &args[0], NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi );
    2726    CloseHandle( pi.hProcess );
    2827    CloseHandle( pi.hThread );
    2928}
     29
     30#ifdef HAVE_WINDOWS_7_SDK
     31
     32#define MSGFLT_ADD 1
     33
     34#pragma push_macro("_WIN32_WINNT")
     35#undef _WIN32_WINNT
     36#define _WIN32_WINNT 0x0601
     37#include <dwmapi.h>
     38#pragma pop_macro("_WIN32_WINNT")
     39
     40#define WM_DWMSENDICONICTHUMBNAIL 0x0323
     41#define WM_DWMSENDICONICLIVEPREVIEWBITMAP 0x0326
     42
     43// Windows 7タスクバーにボタンとして表示させるためのウィンドウ。
     44// 各MDI子ウィンドウ (wndTarget) と1対1に対応する。
     45class DummyWindowForTaskbarButton : public ATL::CWindowImpl<DummyWindowForTaskbarButton>, boost::noncopyable
     46{
     47public:
     48    DECLARE_WND_CLASS(TEXT("DummyWindow For Taskbar Button"));
     49
     50    BEGIN_MSG_MAP(DummyWindowForTaskbarButton)
     51        MESSAGE_HANDLER_EX(WM_DWMSENDICONICTHUMBNAIL, OnDwmSendIconicThumnail)
     52        MESSAGE_HANDLER_EX(WM_DWMSENDICONICLIVEPREVIEWBITMAP, OnDwmSendIconicLivePreviewBitmap)
     53        MSG_WM_ACTIVATE(OnActivate)
     54    END_MSG_MAP()
     55
     56    explicit DummyWindowForTaskbarButton(HWND hwndTarget, const char* title) :
     57        wndTarget(hwndTarget)
     58    {
     59        HWND hwndDummy = Create( hOwner, CRect( -32000, -32000, 1, 1 ), title,
     60            WS_BORDER | WS_SYSMENU | WS_CAPTION, WS_EX_NOACTIVATE);
     61        SetIcon( wndTarget.GetIcon( FALSE ), FALSE );
     62        SetIcon( wndTarget.GetIcon( TRUE ), TRUE );
     63
     64        BOOL iconicRepresentation = TRUE;
     65        HRESULT hr;
     66        hr = DwmSetWindowAttribute(
     67            *this,
     68            DWMWA_FORCE_ICONIC_REPRESENTATION,
     69            &iconicRepresentation,
     70            sizeof iconicRepresentation);
     71        BOOL iconicBitmap = TRUE;
     72        hr = DwmSetWindowAttribute(
     73            *this,
     74            DWMWA_HAS_ICONIC_BITMAP,
     75            &iconicBitmap,
     76            sizeof iconicBitmap);
     77    }
     78
     79    ~DummyWindowForTaskbarButton()
     80    {
     81    }
     82private:
     83    void OnActivate(UINT state, BOOL /*minimized*/, HWND /*hwndOther*/)
     84    {
     85        if (state == WA_ACTIVE)
     86        {
     87            if (ActiveBasic::IDE::Program::mainFrame.IsIconic())
     88            {
     89                ActiveBasic::IDE::Program::mainFrame.ShowWindow(SW_RESTORE);
     90            }
     91            SetForegroundWindow(ActiveBasic::IDE::Program::mainFrame);
     92            ActiveBasic::IDE::Program::mainFrame.MDIActivate(wndTarget);
     93            wndTarget.Invalidate(FALSE);
     94        }
     95    }
     96
     97    class BitmapMemoryDC : public WTL::CDC, boost::noncopyable
     98    {
     99    public:
     100        explicit BitmapMemoryDC(HBITMAP hbmp) :
     101            WTL::CDC(::CreateCompatibleDC(0)),
     102            bmp(hbmp),
     103            hbmpOld(SelectBitmap(bmp))
     104        {
     105        }
     106        BitmapMemoryDC(int width, int height, void*& bits) :
     107            WTL::CDC(::CreateCompatibleDC(0)),
     108            bmp(CreateDIBSection32(m_hDC, width, height, bits)),
     109            hbmpOld(SelectBitmap(bmp))
     110        {
     111        }
     112        ~BitmapMemoryDC()
     113        {
     114            SelectBitmap(hbmpOld); // この後、CDCとbmpのデストラクタでそれぞれDeleteDCとDeleteObjectがなされる。
     115        }
     116        WTL::CBitmap& GetBitmap()
     117        {
     118            return bmp;
     119        }
     120    private:
     121        WTL::CBitmap bmp;
     122        HBITMAP hbmpOld;
     123    };
     124
     125    LRESULT OnDwmSendIconicThumnail(UINT, WPARAM, LPARAM lp)
     126    {
     127        HRESULT hr = SetIconicThumbnail(HIWORD(lp), LOWORD(lp));
     128        return 0;
     129    }
     130
     131    LRESULT OnDwmSendIconicLivePreviewBitmap(UINT, WPARAM, LPARAM)
     132    {
     133        HRESULT hr = SetIconicLivePreviewBitmap();
     134        return 0;
     135    }
     136
     137    HRESULT SetIconicThumbnail(int maximumWidth, int maximumHeight)
     138    {
     139        int widthBmp, heightBmp;
     140        BitmapMemoryDC dcSrc(CreateBitmap(widthBmp, heightBmp));
     141        if (dcSrc)
     142        {
     143            int width, height;  // dcSrcの縦横比に合わせて縮小する
     144            if (widthBmp * maximumHeight > maximumWidth * heightBmp) // (widthBmp / heightBmp > maximumWidth / maximumHeight)
     145            {
     146                width = maximumWidth;
     147                height = heightBmp * maximumWidth / widthBmp;
     148            }
     149            else
     150            {
     151                height = maximumHeight;
     152                width = widthBmp * maximumHeight / heightBmp;
     153            }
     154            void* pvBits;
     155            BitmapMemoryDC dc(width, height, pvBits);
     156            if (dc)
     157            {
     158                StretchBlt(dc, 0, 0, width, height, dcSrc, 0, 0, widthBmp, heightBmp, SRCCOPY);
     159                return DwmSetIconicThumbnail(*this, dc.GetBitmap(), DWM_SIT_DISPLAYFRAME);
     160            }
     161        }
     162        return HRESULT_FROM_WIN32(GetLastError());
     163    }
     164
     165    HRESULT SetIconicLivePreviewBitmap()
     166    {
     167        int w, h;
     168        WTL::CBitmap bmp(CreateBitmap(w, h));
     169        if (bmp)
     170        {
     171            POINT pt = {};
     172            wndTarget.MapWindowPoints(hOwner, &pt, 1);
     173            pt.y += GetSystemMetrics(SM_CYMENU);
     174            return DwmSetIconicLivePreviewBitmap(*this, bmp, &pt, wndTarget.IsZoomed() ? 0 : DWM_SIT_DISPLAYFRAME);
     175        }
     176        return HRESULT_FROM_WIN32(GetLastError());
     177    }
     178
     179    static void SetAlpha(DWORD& pixel)
     180    {
     181        pixel |= 0xff000000;
     182    }
     183
     184    HBITMAP CreateBitmap(int& width, int& height)
     185    {
     186        RECT rcClient;
     187        wndTarget.GetClientRect(&rcClient);
     188        void* pvBits;
     189        BitmapMemoryDC dc(rcClient.right, rcClient.bottom, pvBits);
     190        if (dc)
     191        {
     192            int wndNum = GetWndNum(wndTarget);
     193            if (wndNum != -1)
     194            {
     195                CPoint origin(0, 0);
     196                wndTarget.ClientToScreen( &origin );
     197                CRect rcWindow;
     198                wndTarget.GetWindowRect( rcWindow );
     199                origin -= rcWindow.TopLeft();
     200                dc.SetWindowOrg( origin ); // クライアント領域の(0, 0)がビットマップの(0, 0)になるよう合わせる
     201                wndTarget.Print( dc, PRF_CHECKVISIBLE | PRF_ERASEBKGND | PRF_CHILDREN | PRF_CLIENT );
     202                width = rcClient.right;
     203                height = rcClient.bottom;
     204                DWORD* pdwBits = static_cast<DWORD*>(pvBits);
     205                std::for_each(pdwBits, pdwBits + width * height, SetAlpha);
     206                return dc.GetBitmap().Detach();
     207            }
     208        }
     209        return 0;
     210    }
     211    // 32ビットトップダウンのDIBセクションを作る補助
     212    static HBITMAP CreateDIBSection32(HDC hdc, int width, int height, void*& pb)
     213    {
     214        BITMAPINFO bi;
     215        ZeroMemory(&bi.bmiHeader, sizeof bi.bmiHeader);
     216        bi.bmiHeader.biSize = sizeof bi.bmiHeader;
     217        bi.bmiHeader.biWidth = width;
     218        bi.bmiHeader.biHeight = -height;  // トップダウンDIBにする必要があるらしい
     219        bi.bmiHeader.biPlanes = 1;
     220        bi.bmiHeader.biBitCount = 32;
     221        return CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, &pb, 0, 0);
     222    }
     223
     224    CWindow wndTarget;
     225};
     226
     227class TaskbarList
     228{
     229    typedef boost::shared_ptr<DummyWindowForTaskbarButton> DummyWindowForTaskbarButtonPtr;
     230    typedef std::map<HWND, DummyWindowForTaskbarButtonPtr> WindowMap;
     231public:
     232    TaskbarList(HWND hwndFrame) :
     233        wndFrame(hwndFrame)
     234    {
     235        HRESULT hr = taskbarList.CoCreateInstance( CLSID_TaskbarList );
     236        if ( FAILED( hr ) ) {
     237            return;
     238        }
     239        HRESULT hr2 = taskbarList->HrInit();
     240        if ( FAILED( hr2 ) ) {
     241            taskbarList.Release();
     242            return;
     243        }
     244    }
     245
     246    void RegisterTab(HWND hwndChild, const char* title)
     247    {
     248        assert( hwndChild );
     249        if (taskbarList)
     250        {
     251            assert( windowMap.find(hwndChild) == windowMap.end() );
     252            DummyWindowForTaskbarButtonPtr p(new DummyWindowForTaskbarButton(hwndChild, title));
     253            windowMap.insert(std::make_pair(hwndChild, p));
     254            //タスクバーボタンに追加
     255            HRESULT hr = taskbarList->RegisterTab(*p, wndFrame);
     256        }
     257    }
     258
     259    void RegisterTab(HWND hwndChild)
     260    {
     261        ATL::CWindow wnd = hwndChild;
     262        ATL::CString title;
     263        wnd.GetWindowText(title);
     264        RegisterTab(hwndChild, title);
     265    }
     266
     267    void UnregisterTab(HWND hwndChild)
     268    {
     269        if (taskbarList)
     270        {
     271            WindowMap::iterator it = windowMap.find(hwndChild);
     272            assert( it != windowMap.end() );
     273            HRESULT hr = taskbarList->UnregisterTab(*it->second);
     274            it->second->DestroyWindow();
     275            windowMap.erase( it );
     276        }
     277    }
     278
     279    void InvalidateIconicBitmaps(HWND hwndChild)
     280    {
     281        DwmInvalidateIconicBitmaps(*mapAt(hwndChild));
     282    }
     283
     284    void SetTabActivate(HWND hwndChild)
     285    {
     286        if (taskbarList)
     287        {
     288            taskbarList->SetTabActive(*mapAt(hwndChild), wndFrame, 0);
     289        }
     290    }
     291
     292    void SetTabOrder( HWND hwndChild, HWND hwndInsertBefore )
     293    {
     294        if (taskbarList)
     295        {
     296        taskbarList->SetTabOrder(*mapAt(hwndChild),
     297            hwndInsertBefore
     298            ? static_cast<HWND>(*mapAt(hwndInsertBefore))
     299            : 0);
     300        }
     301    }
     302private:
     303    DummyWindowForTaskbarButtonPtr mapAt(HWND hwndChild)
     304    {
     305        DummyWindowForTaskbarButtonPtr p = windowMap[hwndChild];
     306        assert(p);
     307        return p;
     308    }
     309    CWindow wndFrame;
     310    ATL::CComPtr<ITaskbarList3> taskbarList;
     311    WindowMap windowMap;
     312};
     313#endif HAVE_WINDOWS_7_SDK
     314
     315#ifdef HAVE_WINDOWS_7_SDK
     316MainFrame::MainFrame() :
     317    TaskbarButtonCreated( RegisterWindowMessage( TEXT("TaskbarButtonCreated") ) )
     318{
     319    if ( TaskbarButtonCreated != 0 )
     320    {
     321        typedef BOOL WINAPI CWMF(UINT, DWORD);
     322        HMODULE hmodUser = GetModuleHandle( TEXT("user32.dll") );
     323        assert( hmodUser != 0 );
     324        if ( CWMF* pcwmf = reinterpret_cast<CWMF*>( GetProcAddress( hmodUser, "ChangeWindowMessageFilter" ) ) )
     325        {
     326            pcwmf(TaskbarButtonCreated, MSGFLT_ADD);
     327            pcwmf(WM_DWMSENDICONICTHUMBNAIL, MSGFLT_ADD);
     328            pcwmf(WM_DWMSENDICONICLIVEPREVIEWBITMAP, MSGFLT_ADD);
     329        }
     330    }
     331}
     332#else
     333MainFrame::MainFrame() {}
     334#endif
    30335
    31336void MainFrame::Resized()
     
    59364    //Status bar
    60365    int height_Statusbar;
    61     SendMessage(hStatusBar,SB_GETRECT,0,(long)&StatusRect);
     366    SendMessage(hStatusBar,SB_GETRECT,0,(LPARAM)&StatusRect);
    62367    height_Statusbar=StatusRect.bottom;
    63368
     
    227532    hOwner = m_hWnd;
    228533    extern WNDPROC oldMainFrameWndProc;
    229     oldMainFrameWndProc = (WNDPROC)::GetWindowLong( hOwner, GWL_WNDPROC );
    230     ::SetWindowLongPtr( hOwner, GWL_WNDPROC, reinterpret_cast<LONG_PTR>(WindowFunc) );
     534    oldMainFrameWndProc = (WNDPROC)::SetWindowLongPtr( hOwner, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowFunc) );
    231535
    232536    SetupWindow(hOwner);
     
    234538    //テキストエディタフォント設定
    235539    ResetTextEditFont(hOwner);
    236 
    237 
    238540
    239541    return 0;
     
    549851void MainFrame::OnPaint( HDC )
    550852{
    551     PAINTSTRUCT ps;
    552     HDC hdc = this->BeginPaint( &ps );
    553 
    554     HBRUSH hBrush = CreateSolidBrush( GetSysColor( COLOR_3DFACE ) );
     853    WTL::CPaintDC dc( m_hWnd );
    555854
    556855    RECT rect;
    557856    this->GetClientRect( &rect );
    558857
    559     FillRect( hdc, &rect, hBrush );
    560 
    561     DeleteObject( hBrush );
    562 
    563     this->EndPaint( &ps );
     858    dc.FillRect( &rect, GetSysColorBrush( COLOR_3DFACE ) );
    564859}
    565860
     
    600895    ::UpdateWindow(hChild);
    601896
    602     char *pTemp=MdiInfo[WndNum]->pMdiTextEdit->buffer;
     897    const char *pTemp=MdiInfo[WndNum]->pMdiTextEdit->buffer;
    603898
    604899    //行の先頭インデックスを取得(取得する行の番号はwParamで渡される)
     
    628923}
    629924
     925::LRESULT MainFrame::OnTaskbarButtonCreated( ::UINT msg, ::WPARAM, ::LPARAM )
     926{
     927#ifdef HAVE_WINDOWS_7_SDK
     928    if ( msg == 0 ) { // 念のため確認
     929        return 0;
     930    }
     931    taskbarList.reset(new TaskbarList(*this));
     932#endif
     933    return 0;
     934}
     935
     936void MainFrame::AddChildWindow( HWND hwndChild )
     937{
     938#ifdef HAVE_WINDOWS_7_SDK
     939    taskbarList->RegisterTab( hwndChild );
     940#endif
     941}
     942
     943void MainFrame::DeleteChildWindow( HWND hwndChild )
     944{
     945#ifdef HAVE_WINDOWS_7_SDK
     946    taskbarList->UnregisterTab( hwndChild );
     947#endif
     948}
     949
     950void MainFrame::ActivateChildWindow( HWND hwndChild )
     951{
     952#ifdef HAVE_WINDOWS_7_SDK
     953    taskbarList->SetTabActivate( hwndChild );
     954#endif
     955}
     956
     957void MainFrame::SetTabOrder( HWND hwndChild, HWND hwndInsertBefore )
     958{
     959#ifdef HAVE_WINDOWS_7_SDK
     960    taskbarList->SetTabOrder( hwndChild, hwndInsertBefore );
     961#endif
     962}
     963
     964void MainFrame::InvalidateBitmap( HWND hwndChild )
     965{
     966#ifdef HAVE_WINDOWS_7_SDK
     967    taskbarList->InvalidateIconicBitmaps( hwndChild );
     968#endif
     969}
     970
    630971void MainFrame::OnCmdNew( UINT uNotifyCode, int nID, CWindow wndCtl )
    631972{
     
    639980    char temporary[MAX_PATH];
    640981
    641     FileType=DialogBox(hResInst,MAKEINTRESOURCE(IDD_NEWFILE),hOwner,(DLGPROC)DlgNewFile);
     982    FileType=DialogBox(hResInst,MAKEINTRESOURCE(IDD_NEWFILE),hOwner,DlgNewFile);
    642983    if(FileType==-1) return;
    643984
     
    7451086{
    7461087    //文字コードを指定して保存
    747     DialogBox(hResInst,MAKEINTRESOURCE(IDD_CODE_SAVE),m_hWnd,(DLGPROC)nkfDlgCodeSave);
     1088    DialogBox(hResInst,MAKEINTRESOURCE(IDD_CODE_SAVE),m_hWnd,nkfDlgCodeSave);
    7481089}
    7491090
    7501091void MainFrame::OnCmdAllSave( UINT uNotifyCode, int nID, CWindow wndCtl )
    7511092{
    752     for( int i=0;i<MdiInfo.size();i++){
    753         if(MdiInfo[i]->hwnd) SaveDocument(MdiInfo[i]->hwnd,NULL);
     1093    foreach( MDIINFO *mi, MdiInfo ){
     1094        if(mi->hwnd) SaveDocument(mi->hwnd,NULL);
    7541095    }
    7551096    if( projectInfo.IsOpened() )
     
    8241165        TextEdit_GetSel(WndNum,&CharRange);
    8251166
    826         HGLOBAL hGlobal=(char *)GlobalAlloc(GMEM_MOVEABLE,CharRange.cpMax-CharRange.cpMin+1);
     1167        HGLOBAL hGlobal=GlobalAlloc(GMEM_MOVEABLE,CharRange.cpMax-CharRange.cpMin+1);
    8271168        char *pTemp=(char *)GlobalLock(hGlobal);
    8281169        memcpy(pTemp,MdiInfo[WndNum]->pMdiTextEdit->buffer+CharRange.cpMin,CharRange.cpMax-CharRange.cpMin);
     
    8851226        TextEdit_GetSel(WndNum,&CharRange);
    8861227
    887         HGLOBAL hGlobal=(char *)GlobalAlloc(GMEM_MOVEABLE,CharRange.cpMax-CharRange.cpMin+1);
     1228        HGLOBAL hGlobal=GlobalAlloc(GMEM_MOVEABLE,CharRange.cpMax-CharRange.cpMin+1);
    8881229        char *pTemp=(char *)GlobalLock(hGlobal);
    8891230        memcpy(pTemp,MdiInfo[WndNum]->pMdiTextEdit->buffer+CharRange.cpMin,CharRange.cpMax-CharRange.cpMin);
     
    10301371void MainFrame::OnCmdFind( UINT uNotifyCode, int nID, CWindow wndCtl )
    10311372{
    1032     DialogBox(hResInst,MAKEINTRESOURCE(IDD_FIND),m_hWnd,(DLGPROC)DlgFind);
     1373    DialogBox(hResInst,MAKEINTRESOURCE(IDD_FIND),m_hWnd,DlgFind);
    10331374}
    10341375
    10351376void MainFrame::OnCmdPermutation( UINT uNotifyCode, int nID, CWindow wndCtl )
    10361377{
    1037     DialogBox(hResInst,MAKEINTRESOURCE(IDD_PERMUTATION),m_hWnd,(DLGPROC)DlgPermutation);
     1378    DialogBox(hResInst,MAKEINTRESOURCE(IDD_PERMUTATION),m_hWnd,DlgPermutation);
    10381379}
    10391380
     
    10461387void MainFrame::OnCmdStringCount( UINT uNotifyCode, int nID, CWindow wndCtl )
    10471388{
    1048     DialogBoxParam(hResInst,MAKEINTRESOURCE(IDD_STRING_COUNT),m_hWnd,(DLGPROC)DlgStringCount,0);
     1389    DialogBoxParam(hResInst,MAKEINTRESOURCE(IDD_STRING_COUNT),m_hWnd,DlgStringCount,0);
    10491390}
    10501391
    10511392void MainFrame::OnCmdSelStringCount( UINT uNotifyCode, int nID, CWindow wndCtl )
    10521393{
    1053     DialogBoxParam(hResInst,MAKEINTRESOURCE(IDD_STRING_COUNT),m_hWnd,(DLGPROC)DlgStringCount,1);
     1394    DialogBoxParam(hResInst,MAKEINTRESOURCE(IDD_STRING_COUNT),m_hWnd,DlgStringCount,1);
    10541395}
    10551396#endif
     
    12901631    int idProcess;
    12911632    DWORD dwPlatform;
    1292     idProcess=DialogBoxParam(hResInst,MAKEINTRESOURCE(IDD_ATTACH),m_hWnd,(DLGPROC)DlgAttach,(LPARAM)&dwPlatform);
     1633    idProcess=DialogBoxParam(hResInst,MAKEINTRESOURCE(IDD_ATTACH),m_hWnd,DlgAttach,(LPARAM)&dwPlatform);
    12931634    if(idProcess==0) return;
    12941635
     
    15521893void MainFrame::OnCmdAbout( UINT uNotifyCode, int nID, CWindow wndCtl )
    15531894{
    1554     DialogBox(hResInst,MAKEINTRESOURCE(IDD_ABOUT),m_hWnd,(DLGPROC)DialogAbout);
     1895    DialogBox(hResInst,MAKEINTRESOURCE(IDD_ABOUT),m_hWnd,DialogAbout);
    15551896}
    15561897
     
    16111952    //このウィンドウ以外をすべて閉じる(&A)
    16121953    HWND hChild=::GetWindow(hClient,GW_CHILD);
    1613     int WndNum=GetWndNum(hChild);
    1614     for(int i=0;i<MdiInfo.size();i++){
    1615         if(i==WndNum) continue;
    1616         if(MdiInfo[i]->hwnd) SendMessage(MdiInfo[i]->hwnd,WM_CLOSE,0,0);
     1954    foreach ( MDIINFO *mi, MdiInfo ){
     1955        if ( mi->hwnd == hChild ){
     1956            continue;
     1957        }
     1958        if(mi->hwnd){
     1959            ::PostMessage( mi->hwnd, WM_CLOSE, 0, 0 );
     1960            //foreachの最中に削除されるとイテレータが回らないのでSendを使っていない。
     1961        }
    16171962    }
    16181963}
Note: See TracChangeset for help on using the changeset viewer.