//--------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation 1991-1992 // //--------------------------------------------------------------------------- #include "cabinet.h" // // Initialize GUIDs (should be done only and at-least once per DLL/EXE) // // We need IUnknown from coguid, all shell GUID's from shlguid, and // IDropTarget from oleguid // #pragma data_seg(DATASEG_READONLY) #include #include //#define INITGUID //#include //#include #pragma data_seg() #include "drivlist.h" #include "rcids.h" #include "tree.h" #pragma data_seg(DATASEG_READONLY) #ifdef _WIN32 const TBBUTTON c_tbExplorer[] = { // FCIDM_DRIVELIST iBitmap is patched up to the real width as we insert it { 0, FCIDM_DRIVELIST, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1 }, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP , {0,0}, 0, -1 }, { VIEW_PARENTFOLDER, FCIDM_PREVIOUSFOLDER, TBSTATE_ENABLED, (BYTE) TBSTYLE_BUTTON, {0,0}, 0, -1 }, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP , {0,0}, 0, -1 }, }; #else const TBBUTTON c_tbExplorer[] = { // FCIDM_DRIVELIST iBitmap is patched up to the real width as we insert it { 0, FCIDM_DRIVELIST, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1 }, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1 }, { VIEW_PARENTFOLDER, FCIDM_PREVIOUSFOLDER, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1 }, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1 }, }; #endif #pragma data_seg() extern const TCHAR c_szTemplateD[]; HRESULT STDMETHODCALLTYPE CFileCabinet_QueryInterface(IShellBrowser * psb, REFIID riid, LPVOID FAR* ppvObj) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); if (IsEqualIID(riid, &IID_IShellBrowser) || IsEqualIID(riid, &IID_IUnknown)) { *ppvObj = psb; this->cRef++; return NOERROR; } *ppvObj = NULL; return ResultFromScode(E_NOINTERFACE); } ULONG STDMETHODCALLTYPE CFileCabinet_AddRef(IShellBrowser * psb) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); this->cRef++; return this->cRef; } ULONG STDMETHODCALLTYPE CFileCabinet_Release(IShellBrowser * psb) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); this->cRef--; if (this->cRef > 0) { return this->cRef; } if (this->pidl) ILFree(this->pidl); LocalFree((HLOCAL)this); return 0; } STDMETHODIMP CFileCabinet_GetWindow(LPSHELLBROWSER psb, HWND FAR* phwnd) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); *phwnd = this->hwndMain; return NOERROR; } STDMETHODIMP CFileCabinet_ContextSensitiveHelp(LPSHELLBROWSER psb, BOOL fEnable) { // BUGBUG: Implement it later! return ResultFromScode(E_NOTIMPL); } STDMETHODIMP CFileCabinet_SetStatusText(LPSHELLBROWSER psb, LPCOLESTR pwch) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); TCHAR szHint[256]; #if defined(WINDOWS_ME) szHint[0]= TEXT('\t'); szHint[1]= TEXT('\t'); szHint[2]= TEXT('\0'); if (pwch) { OleStrToStrN(&szHint[2], ARRAYSIZE(szHint)-2, pwch, (UINT)-1); } SendMessage(this->hwndStatus, SB_SETTEXT, SBT_RTLREADING | SBT_NOBORDERS | 255, (LPARAM)(LPTSTR)szHint); #else szHint[0]= TEXT('\0'); if (pwch) { OleStrToStrN(szHint, ARRAYSIZE(szHint), pwch, (UINT)-1); } SendMessage(this->hwndStatus, SB_SETTEXT, SBT_NOBORDERS | 255, (LPARAM)(LPTSTR)szHint); #endif SendMessage(this->hwndStatus, SB_SIMPLE, 1, 0L); return NOERROR; } STDMETHODIMP CFileCabinet_EnableModeless(LPSHELLBROWSER psb, BOOL fEnable) { // We have no modeless window to be disabled/enabled. return NOERROR; } STDMETHODIMP CFileCabinet_TranslateAccelerator(LPSHELLBROWSER psb, LPMSG pmsg, WORD wID) { // We don't support EXE embedding. return NOERROR; } STDMETHODIMP CFileCabinet_BrowseObject(LPSHELLBROWSER psb, LPCITEMIDLIST pidl, UINT wFlags) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); HRESULT hres = NOERROR; LPITEMIDLIST pidlNew; Assert(SBSP_PARENT && SBSP_SAMEBROWSER); // an assumption #if 0 // // Special case "go to parent using the same browser" // if ((wFlags & SBSP_PARENT) && (wFlags & SBSP_SAMEBROWSER)) { Cabinet_ViewFolder(this, TRUE); return NOERROR; } #endif pidlNew = NULL; switch(wFlags & (SBSP_RELATIVE|SBSP_ABSOLUTE|SBSP_PARENT)) { case SBSP_RELATIVE: pidlNew = ILCombine(this->pidl, pidl); break; case SBSP_PARENT: pidlNew = ILClone(this->pidl); ILRemoveLastID(pidlNew); // ILRemoveLastID can handle NULL/empty pidl break; default: Assert(FALSE); case SBSP_ABSOLUTE: // Note that this->pidl should already be translated for the other // cases // This NULL's pidlNew if it fails OTTranslateIDList(pidl, &pidlNew); break; } if (pidlNew) { NEWFOLDERINFO fi; switch (wFlags & (SBSP_OPENMODE|SBSP_EXPLOREMODE|SBSP_DEFMODE)) { case SBSP_OPENMODE: fi.uFlags = COF_NORMAL; break; case SBSP_EXPLOREMODE: fi.uFlags = COF_EXPLORE; break; default: Assert(FALSE); case SBSP_DEFMODE: fi.uFlags = this->hwndTree ? COF_EXPLORE : COF_NORMAL; break; } switch (wFlags & (SBSP_NEWBROWSER|SBSP_SAMEBROWSER|SBSP_DEFBROWSER)) { default: Assert(FALSE); case SBSP_DEFBROWSER: if (g_CabState.fNewWindowMode && !this->hwndTree) { goto DoOpenFolder; } // Fall through case SBSP_SAMEBROWSER: // Post the SetPath back to ourselves so we do not free the // ShellView while it is calling us Cabinet_SetPath(this, CSP_REPOST, pidlNew); break; case SBSP_NEWBROWSER: fi.uFlags |= COF_CREATENEWWINDOW; goto DoOpenFolder; DoOpenFolder: fi.hwndCaller = this->hwndMain; fi.pidl = pidlNew; fi.uFlags |= COF_NOTRANSLATE; fi.nShow = SW_NORMAL; fi.dwHotKey = 0; Cabinet_OpenFolder(&fi); break; } ILFree(pidlNew); Assert(hres==NOERROR); } else { hres = ResultFromScode(E_OUTOFMEMORY); } return hres; } #undef ILIsEqual int CDECL MRUILIsEqual(const void *pidl1, const void *pidl2, size_t cb) { // First cheap hack to see if they are 100 percent equal for performance int iCmp; if ((iCmp=memcmp(pidl1, pidl2, cb)) == 0) return(0); if (ILIsEqual(pidl1, pidl2)) return 0; else return iCmp; } //---------------------------------------------------------------------------- // // REVIEW: we may want to keep the hmru open for the life of the shell // to avoid having to flush the registry info. // // creates a stream on a given value of the pidl MRU // // the MRU is based on the pidl passed in // // in: // pidl the MRU is based on this // grfMode open mode (read/write) for the stream // pszStreamName the name of the stream to use. this is the value name // under the stream key that the stream data is stored in. // LPSTREAM Cabinet_GetViewStreamForPidl(LPCITEMIDLIST pidlRelToRoot, DWORD grfMode, LPCTSTR pszStreamName) { LPSTREAM pstm = NULL; HANDLE hmru = NULL; int iFoundSlot = -1, iNewSlot; TCHAR szValue[CCHSZSHORT]; UINT cbPidl; LPITEMIDLIST pidlCombine = NULL; LPCITEMIDLIST pidl, pidlRoot; BOOL bDesktopItem = FALSE; LPITEMIDLIST pidlDesktop; #pragma warning (disable: 4113) // We are initializing a MRUINFO struct with a MRUCMPDATAPROC rather than // a MRUCMPPROC function pointer (the MRU_BINARY flag indicates this to // whoever winds up using it). Since the compiler doesn't like this, we // disable the warning temporarily. MRUINFO mi = { SIZEOF(MRUINFO), 50, // we store this many view streams MRU_BINARY, HKEY_CURRENT_USER, c_szCabinetStreamMRU, (MRUCMPDATAPROC)MRUILIsEqual, }; #pragma warning (default: 4113) Assert(pidlRelToRoot); pidlRoot = Desktop_GetRootPidl(); if (pidlRoot) { pidlCombine = ILCombine(pidlRoot, pidlRelToRoot); if (!pidlCombine) { goto Error1; } pidl = pidlCombine; } else { pidl = pidlRelToRoot; } // Check to see if the object is rooted from the desktop directory (*NOT* the desktop // PIDL which would match for all objects). If the items parent is the desktop directory // then we change to using the Desktop MRU. // // This basicly allows these items to exist, and not be flushed out by browsing // assorted other resources. // TODO: allow special casing via the registry at some point for special folders // TODO: (control panels and fonts etc?). pidlDesktop = SHCloneSpecialIDList( NULL, CSIDL_DESKTOPDIRECTORY, TRUE ); if ( pidlDesktop ) { TCHAR szDesktopPath[MAX_PATH]; TCHAR szObjectPath[MAX_PATH]; SHGetPathFromIDList( pidl, szObjectPath); SHGetPathFromIDList( pidlDesktop, szDesktopPath); if ( StrCmpNI( szObjectPath, szDesktopPath, lstrlen(szDesktopPath) ) == 0) { bDesktopItem = TRUE; // item is desktop relative mi.lpszSubKey = c_szDesktopCabinetStreamMRU; // therefore modify the key } ILFree( pidlDesktop ); } // Now lets try to save away the other information associated with view. hmru = CreateMRUList(&mi); if (!hmru) return NULL; cbPidl = ILGetSize(pidl); FindMRUData(hmru, pidl, cbPidl, &iFoundSlot); // Did we find the item? if (iFoundSlot<0 && ((grfMode & (STGM_READ|STGM_WRITE|STGM_READWRITE)) == STGM_READ)) { // Do not create the stream if it does not exist and we are // only reading } else { HKEY hkCabStreams, hkValues; TCHAR szSubVal[64]; DWORD dwSize, dwType; // Note that we always create the key here, since we have // already checked whether we are just reading and the MRU // thing does not exist if (RegCreateKey(g_hkeyExplorer, bDesktopItem ? c_szDesktopCabinetStreams : c_szCabinetStreams, &hkCabStreams) == ERROR_SUCCESS) { iNewSlot = AddMRUData(hmru, pidl, cbPidl); wsprintf(szValue, c_szTemplateD, iNewSlot); if (iFoundSlot<0 && RegOpenKey(hkCabStreams, szValue, &hkValues)==ERROR_SUCCESS) { // This means that we have created a new MRU // item for this PIDL, so clear out any // information residing at this slot // Note that we do not just delete the key, // since that could fail if it has any sub-keys while (dwSize=ARRAYSIZE(szSubVal), RegEnumValue(hkValues, 0, szSubVal, &dwSize, NULL, &dwType, NULL, NULL) == ERROR_SUCCESS) { if (RegDeleteValue(hkValues, szSubVal) != ERROR_SUCCESS) { break; } } RegCloseKey(hkValues); } pstm = OpenRegStream(hkCabStreams, szValue, pszStreamName, grfMode); RegCloseKey(hkCabStreams); } } if (pidlCombine) { ILFree(pidlCombine); } Error1:; FreeMRUList(hmru); return(pstm); } STDMETHODIMP CFileCabinet_GetViewStateStream(IShellBrowser * psb, DWORD grfMode, LPSTREAM *pStrm) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); if (this->pidl) { // And call off to get the stream associated with the path. // Note that we store all Cabinet related information (window position, // toolbar state, etc.) under c_szCabStreamInfo, while view specific // information is stored under c_szViewStreamInfo. *pStrm = Cabinet_GetViewStreamForPidl(this->pidl, grfMode, c_szViewStreamInfo); } else { DebugMsg(DM_ERROR, TEXT("c.cfc_gvss: Unable to get view stream for given PIDL.")); *pStrm = NULL; } return *pStrm ? NOERROR : ResultFromScode(E_OUTOFMEMORY); } // Get the handles of various windows in the File Cabinet // HWND STDMETHODCALLTYPE FC_GetWindow(IShellBrowser * psb, UINT uWindow) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); switch (uWindow) { case FCW_TOOLBAR: return this->hwndToolbar; case FCW_STATUS: return this->hwndStatus; case FCW_TREE: return this->hwndTree; #ifdef WANT_TABS case FCW_TABS: return this->hwndTabs; #endif case FCW_VIEW: return this->hwndView; case FCW_BROWSER: return this->hwndMain; } return NULL; } HWND FC_GetControlWindow(CFileCabinet * this, UINT id) { HWND hwndControl = NULL; switch (id) { case FCW_TOOLBAR: hwndControl = this->hwndToolbar; break; case FCW_STATUS: hwndControl = this->hwndStatus; break; case FCW_TREE: hwndControl = this->hwndTree; break; } return hwndControl; } STDMETHODIMP CFileCabinet_GetControlWindow(LPSHELLBROWSER psb, UINT id, HWND FAR* lphwnd) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); *lphwnd = FC_GetControlWindow(this, id); return NOERROR; } STDMETHODIMP CFileCabinet_SendControlMsg(LPSHELLBROWSER psb, UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT FAR* pret) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); HWND hwndControl = FC_GetControlWindow(this, id); if (hwndControl) { LRESULT ret = SendMessage(hwndControl, uMsg, wParam, lParam); if (pret) { *pret = ret; } return NOERROR; } return ResultFromScode(E_INVALIDARG); } STDMETHODIMP CFileCabinet_QueryActiveShellView(LPSHELLBROWSER psb, LPSHELLVIEW * ppsv) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); // // We have both psv and hwndView after the completion of view creation. // if (this->psv && this->hwndView) { *ppsv = this->psv; this->psv->lpVtbl->AddRef(this->psv); return NOERROR; } *ppsv = NULL; return ResultFromScode(E_FAIL); } void SetWindowStates(PFileCabinet pfc) { int nShowCmd; // Show or hide the menu and sub windows // if (pfc->hmenuCur) { #ifdef WANT_MENUONOFF SetMenu(pfc->hwndMain, pfc->wv.bMenuBar ? pfc->hmenuCur : NULL); #else // WANT_MENUONOFF SetMenu(pfc->hwndMain, pfc->hmenuCur); #endif // WANT_MENUONOFF // SetMenu already does a draw unless this is called to refresh // the menu.. in which case it's the wrong thing to call. //DrawMenuBar(pfc->hwndMain); } // move this to initialize toolbar. if (pfc->hwndToolbar) { nShowCmd = pfc->wv.bToolBar ? SW_SHOW : SW_HIDE; ShowWindow(pfc->hwndToolbar, nShowCmd); } if (pfc->hwndStatus) { nShowCmd = pfc->wv.bStatusBar ? SW_SHOW : SW_HIDE; ShowWindow(pfc->hwndStatus, nShowCmd); } #ifdef WANT_TABS if (pfc->hwndTabs) ShowWindow(pfc->hwndTabs, fFlags & FWF_TABS ? SW_SHOW : SW_HIDE); #endif nShowCmd = g_CabState.fDontShowDescBar ? SW_HIDE : SW_SHOW; if (pfc->hwndTreeTitle) { ShowWindow(pfc->hwndTreeTitle, nShowCmd); } if (pfc->hwndViewTitle) { ShowWindow(pfc->hwndViewTitle, nShowCmd); } // Place all windows correctly // Cabinet_NewSize(pfc, TRUE); } #ifdef WANT_MENUONOFF void _SetupSysMenu(HWND hWnd, HMENU hmenu) { HMENU hmenuSys; TCHAR szString[CCHSZSHORT]; if (hmenu) { // First reset the system menu, then get a modifiable copy // GetSystemMenu(hWnd, TRUE); hmenuSys = GetSystemMenu(hWnd, FALSE); // put a few special menu cmds on the sys menu // steal the text from the regular menu if (hmenuSys) { AppendMenu(hmenuSys, MF_SEPARATOR, 0, NULL); szString[0] = TEXT('\0'); // GetMenuString(hmenu, FCIDM_VIEWMENU, szString, ARRAYSIZE(szString), MF_BYCOMMAND); LoadString(hinstCabinet, IDS_MENUBAR, szString, ARRAYSIZE(szString)); if (szString[0]) { AppendMenu(hmenuSys, MF_ENABLED | MF_STRING, FCIDM_VIEWMENU, szString); szString[0] = TEXT('\0'); } GetMenuString(hmenu, FCIDM_VIEWTOOLBAR, szString, ARRAYSIZE(szString), MF_BYCOMMAND); if (szString[0]) { AppendMenu(hmenuSys, MF_ENABLED | MF_STRING, FCIDM_VIEWTOOLBAR, szString); szString[0] = TEXT('\0'); } } } } #endif // WANT_MENUONOFF STDMETHODIMP CFileCabinet_OnViewWindowActive(LPSHELLBROWSER psb, LPSHELLVIEW psv) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); // REVIEW: This is an assert for ISVs. Should we print nice error messages? Assert(this->psv == psv); if (this->psv == psv) { CFileCabinet_OnFocusChange(this, FOCUS_VIEW); return NOERROR; } return ResultFromScode(E_INVALIDARG); } STDMETHODIMP CFileCabinet_InsertMenus(LPSHELLBROWSER psb, HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); DebugMsg(DM_TRACE, TEXT("sh TR - CFileCabinet::InsertMenus called")); if (hmenuShared) { Shell_MergeMenus(hmenuShared, Cabinet_MenuTemplate(this->uFocus==FOCUS_VIEW, (BOOL)this->hwndTree), 0, 0, FCIDM_BROWSERLAST, MM_SUBMENUSHAVEIDS); lpMenuWidths->width[0] = 1; // File lpMenuWidths->width[2] = 2; // Edit, View lpMenuWidths->width[4] = 2; // Tools, Help // // We don't have "Tools", if this is not an explorer. // if (this->hwndTree == NULL) { lpMenuWidths->width[4] = 1; // Help } } return(ResultFromScode(E_NOTIMPL)); } // // This function is called, when either tree control or the drives // get the focus. // void CFileCabinet_OnFocusChange(PFileCabinet pfc, UINT uFocus) { DebugMsg(DM_TRACE, TEXT("sh TR - CFileCabinet_OnFocusChange (%d -> %d)"), pfc->uFocus, uFocus); if (pfc->uFocus != uFocus) { UINT uFocusPrev = pfc->uFocus; // // If the view is loosing the focus (within the explorer), // we should let it know. We should update pfc->uFocus before // calling UIActivate, because it will call our InsertMenu back. // pfc->uFocus = uFocus; if (uFocusPrev==FOCUS_VIEW) { pfc->psv->lpVtbl->UIActivate(pfc->psv, SVUIA_ACTIVATE_NOFOCUS); } } } STDMETHODIMP CFileCabinet_SetMenu(LPSHELLBROWSER psb, HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); if (this->hwndView==NULL && hmenuShared!=NULL) { DebugMsg(DM_TRACE, TEXT("sh TR - CFileCabinet::SetMenus(%x) called when this->hwndView==NULL"), hmenuShared); Assert(0); return ResultFromScode(E_FAIL); } DebugMsg(DM_TRACE, TEXT("sh TR - CFileCabinet::SetMenus(%x) called (when this->hwndView==%x)"), hmenuShared, this->hwndView); if (hmenuShared) { this->hmenuCur = hmenuShared; } else { this->hmenuCur = Cabinet_MenuTemplate(TRUE, (BOOL)this->hwndTree); } SetMenu(this->hwndMain, this->hmenuCur); return NOERROR; } STDMETHODIMP CFileCabinet_RemoveMenus(LPSHELLBROWSER psb, HMENU hmenuShared) { // No need to remove them, because we "copied" them in InsertMenu. DebugMsg(DM_TRACE, TEXT("sh TR - CFileCabinet::RemoveMenus called")); return NOERROR; } int DrivesComboWidth() { HDC hdc = GetDC(NULL); int iWidth = GetDeviceCaps(hdc, LOGPIXELSY) * 2; ReleaseDC(NULL, hdc); return iWidth; } void PositionDrivesCombo(CFileCabinet *this, int nFirstDiff) { int nDriveList = (int)SendMessage(this->hwndToolbar, TB_COMMANDTOINDEX, FCIDM_DRIVELIST, 0L); if (nDriveList >= nFirstDiff) { RECT rcToolbar, rcDrives; SendMessage(this->hwndToolbar, TB_GETITEMRECT, nDriveList, (LPARAM)(LPTSTR)&rcToolbar); // center the drivelist vertically GetWindowRect(this->hwndDrives, &rcDrives); rcDrives.bottom -= rcDrives.top; rcDrives.left = rcToolbar.left; rcDrives.right = rcToolbar.right - rcToolbar.left; GetClientRect(this->hwndToolbar, &rcToolbar); rcDrives.top = (rcToolbar.bottom - rcDrives.bottom) / 2; // We try to reduce flickering by "hiding" the toolbar // when we move the drives list // SetWindowPos(this->hwndDrives, NULL, rcDrives.left, rcDrives.top, rcDrives.right, DrivesComboWidth(), SWP_NOZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE); } } STDMETHODIMP CFileCabinet_SetToolbarItems(IShellBrowser *psb, LPTBBUTTON pViewButtons, UINT nButtons, UINT uFlags) { CFileCabinet * this = IToClassN(CFileCabinet, sb, psb); LPTBBUTTON pStart, pbtn; TBBUTTON tbTemp; int nFirstDiff, nTotalButtons; BOOL bVisible; if (uFlags & FCT_CONFIGABLE) { PositionDrivesCombo(this, 0); InvalidateRect(this->hwndToolbar, NULL, TRUE); return NOERROR; } // Allocate buffer for the default buttons plus the ones passed in // pStart = Alloc(SIZEOF(c_tbExplorer) + (nButtons * SIZEOF(TBBUTTON))); if (!pStart) return NOERROR; pbtn = pStart; nTotalButtons = 0; if (uFlags & FCT_MERGE) { int i; // copy buttons (and offset bitmap indexes) for (i = 0; i < ARRAYSIZE(c_tbExplorer); i++) { pbtn[i] = c_tbExplorer[i]; if (!(c_tbExplorer[i].fsStyle & TBSTYLE_SEP)) pbtn[i].iBitmap += this->iTBOffset; } // special case drives combo Assert(pbtn->idCommand == FCIDM_DRIVELIST); pbtn->iBitmap = DrivesComboWidth(); pbtn += ARRAYSIZE(c_tbExplorer); nTotalButtons += ARRAYSIZE(c_tbExplorer); } if (pViewButtons) { int i; for (i = nButtons - 1; i >= 0; --i) { // copy in the callers buttons // pbtn[i] = pViewButtons[i]; } pbtn += nButtons; nTotalButtons += nButtons; } // Search for the first button that is different (and update states) for (nFirstDiff = 0; nFirstDiff < nTotalButtons; ++nFirstDiff) { if (!SendMessage(this->hwndToolbar, TB_GETBUTTON, nFirstDiff, (LPARAM)&tbTemp)) break; // Check for a separator of the default width // HACKHACK: we have 8 hard coded here, when we should be // getting it from the toolbar in some way // if ((tbTemp.fsStyle & TBSTYLE_SEP) && tbTemp.iBitmap == 8 && pStart[nFirstDiff].iBitmap == 0) { tbTemp.iBitmap = 0; } if (tbTemp.iBitmap != pStart[nFirstDiff].iBitmap || tbTemp.idCommand != pStart[nFirstDiff].idCommand || tbTemp.fsStyle != pStart[nFirstDiff].fsStyle || tbTemp.dwData != pStart[nFirstDiff].dwData || tbTemp.iString != pStart[nFirstDiff].iString) { // If there is something different about this button ... break; } // Note that we can change the state on the fly SendMessage(this->hwndToolbar, TB_SETSTATE, nFirstDiff, pStart[nFirstDiff].fsState); } // We want the toolbar to be completely up-to-date at this point UpdateWindow(this->hwndToolbar); // Save the redraw flag for later restoration bVisible = Cabinet_IsVisible(this->hwndToolbar); if (bVisible) SendMessage(this->hwndToolbar, WM_SETREDRAW, 0, 0L); while (SendMessage(this->hwndToolbar, TB_DELETEBUTTON, nFirstDiff, 0L)) { // Delete all changed buttons } // Add all changed buttons if (nFirstDiff != nTotalButtons) { SendMessage(this->hwndToolbar, TB_ADDBUTTONS, nTotalButtons - nFirstDiff, (LPARAM)(pStart + nFirstDiff)); } Free(pStart); // Show the drives window if necessary. // Note that if nDriveList < i, then its position was unchanged from the // last viewer // PositionDrivesCombo(this, nFirstDiff); // At this point we make sure all the buttons have the right state, // and we show them all since the SetWindowPos below will cause a // repaint. // if (bVisible) { RECT rcToolbar, rcFirstDiff; SendMessage(this->hwndToolbar, WM_SETREDRAW, 1, 0L); GetClientRect(this->hwndToolbar, &rcToolbar); if (nFirstDiff) { SendMessage(this->hwndToolbar, TB_GETITEMRECT, nFirstDiff - 1, (LPARAM)(LPRECT)&rcFirstDiff); rcToolbar.left = rcFirstDiff.right; } InvalidateRect(this->hwndToolbar, &rcToolbar, TRUE); } return NOERROR; } void FileCabinet_CycleFocus(PFileCabinet this) { // these must be in the order of FOCUS_* HWND FocusList[] = { this->hwndView, this->hwndTree, this->hwndDrives }; int i; if (!this->hwndTree) { FocusList[1] = NULL; } if (!this->hwndDrives || !IsWindowVisible(this->hwndDrives)) { FocusList[2] = NULL; } else if (GetFocus() == this->hwndDrives) { this->uFocus = FOCUS_DRIVES; } i = (int)this->uFocus; for (;i < 10;) { if (GetAsyncKeyState(VK_SHIFT) < 0) i++; else i+=2; if (FocusList[i % 3]) break; } i %= 3; if (i == (int)FOCUS_DRIVES) { this->uFocus = FOCUS_DRIVES; } SetFocus(FocusList[i]); } // // Constructor of CFileCabinet class. // // Note this is not really OLE2 complient, but I don't really care since // it is only internal // // History: // 01-12-93 GeorgeP Created // #pragma data_seg(DATASEG_READONLY) IShellBrowserVtbl s_FCSVtbl = { // *** IUnknown methods *** CFileCabinet_QueryInterface, CFileCabinet_AddRef, CFileCabinet_Release, // *** IOleWindow methods *** CFileCabinet_GetWindow, CFileCabinet_ContextSensitiveHelp, // *** IShellBrowser methods *** CFileCabinet_InsertMenus, CFileCabinet_SetMenu, CFileCabinet_RemoveMenus, CFileCabinet_SetStatusText, CFileCabinet_EnableModeless, CFileCabinet_TranslateAccelerator, CFileCabinet_BrowseObject, CFileCabinet_GetViewStateStream, CFileCabinet_GetControlWindow, CFileCabinet_SendControlMsg, CFileCabinet_QueryActiveShellView, CFileCabinet_OnViewWindowActive, CFileCabinet_SetToolbarItems, }; #pragma data_seg() // REVIEW - There's another one like this in desktop.c // Create a "file cabinet" object, which should hold all state info // PFileCabinet CreateFileCabinet(HWND hwndMain, BOOL fExplorer) { PFileCabinet pfc = (PFileCabinet)LocalAlloc(LPTR, SIZEOF(CFileCabinet)); if (pfc) { pfc->sb.lpVtbl = &s_FCSVtbl; // const->non const pfc->cRef = 1; pfc->hwndMain = hwndMain; //pfc->hmenuCur = NULL; //pfc->hwndView = NULL; Assert(pfc->uFocus == FOCUS_VIEW); //pfc->wLastParam = 0; //pfc->lLastParam = 0; //pfc->lpndOpen = NULL; } return pfc; } // // internal CoCreateInstance. // // Note that SHCoCreateInstance can handle classes in SHELL32 even if the // registry is messed up // HRESULT ICoCreateInstance(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv) { return(SHCoCreateInstance(NULL, rclsid, NULL, riid, ppv)); }