//=========================================================== // WBDLL - Helper dll for Winbar // // Copyright (C) 1995 Ziff-Davis Publishing Company // First published in PC Magazine by Douglas Boling // // Revision History // // 1.0 Initial Release //=========================================================== //----------------------------------------------------------- // Include files //----------------------------------------------------------- #include "windows.h" #include "stdlib.h" #include "string.h" #define INT int #include "wbdll.h" #include "winbar.h" INT PILibHookCtl (BOOL); void ComputeIconPos (HWND, LPPOINT); void ArrangeIcons (void); LONG CALLBACK TaskSCProc (HWND, UINT, UINT, LONG); FARPROC MySubClassWindow (HWND, FARPROC); //----------------------------------------------------------- // Global data for control panel applet. //----------------------------------------------------------- HANDLE hInst; HWND hEXEWnd = 0; HINSTANCE hEXEInst = 0; HHOOK hShellHook = 0; // Hook handles HHOOK hCallHook = 0; FARPROC lpfnOldTaskWndProc; // Subclass pointer INT sCxDesk, sCyDesk, sCxIcon, sCyIcon, sCxISpacing, sCyISpacing; INT sCyFrame, sCyDlgFrame, sCyBorder; INT sHeight, sMaxHeight; char szDebug[256]; //============================================================ // DLL External Entry points and support routines //============================================================ //============================================================ // LibMain -- Entry point called during DLL init //============================================================ INT CALLBACK LibMain (HANDLE hInstance, WORD wDataSeg, WORD wHeapSize, LPSTR lpszCmdLine) { hInst = hInstance; //Get and save desktop size sCxDesk = GetSystemMetrics (SM_CXSCREEN); sCyDesk = GetSystemMetrics (SM_CYSCREEN); //Get and save Icon size and spacing sCxIcon = GetSystemMetrics (SM_CXICON); sCyIcon = GetSystemMetrics (SM_CYICON); sCxISpacing = GetSystemMetrics (SM_CXICONSPACING); sCyISpacing = GetSystemMetrics (SM_CYICONSPACING); //Get and save border heights sCyFrame = GetSystemMetrics (SM_CYFRAME) * 2; sCyDlgFrame = GetSystemMetrics (SM_CYDLGFRAME) * 2; sCyBorder = GetSystemMetrics (SM_CYBORDER) * 2; //Zero handle array ComputeIconPos (0, 0); return 1; } //============================================================ // WEP - DLL termination routine //============================================================ INT CALLBACK WEP (INT nParameter) { PILibHookCtl (FALSE); return 1; } //======================================================================== // Call Window Hook function - Monitors for windows changing to icons. // This is accomplished by checking for WM_WINDOWPOSCHANGING messages, // seeing if the window is being minimized and that the default icon // position is -2, -2. If so, a new position is computed and subbed // into the target position field. //======================================================================== // Structure of info passed by the Message hook typedef struct { LPARAM lParam; WPARAM wParam; UINT msg; HWND hWnd; } MYMHSTRUCT; typedef MYMHSTRUCT far *LPMYMHSTRUCT; VOID FAR PASCAL MsgHookProc (int code, WORD wParam, LONG lParam) { LPMYMHSTRUCT lpms; LPWINDOWPOS lpwp; MINMAXINFO far *lpmm; RECT rect; LONG lStyle; INT sCyB; WORD wMsg; if (code >= 0) { lpms = (LPMYMHSTRUCT) lParam; wMsg = lpms->msg; // Check for MS keboard list key // if ((wMsg == WM_KEYUP) && // (lpms->wParam == 0x005d) && (lpms->lParam & 0x1000)) { /* if (wMsg == WM_KEYUP) { wsprintf (szDebug, "wm_keyup det. wParam %x lParam %x\n", lpms->wParam, lpms->lParam); OutputDebugString (szDebug); if ((lpms->wParam == 0x005d) && (lpms->lParam & 0x1000)) { PostMessage (hEXEWnd, MYMSG_SHELLACTIVATE, wParam, 0); OutputDebugString ("Message sent\n"); } } else */ if (wMsg == WM_WINDOWPOSCHANGING) { lpwp = (LPWINDOWPOS) lpms->lParam; if (!IsWindow(lpwp->hwnd)) return; if (!(lpwp->flags & SWP_NOSIZE) && IsIconic (lpwp->hwnd) && (lpwp->x == -2) && (lpwp->y == -2)) { ComputeIconPos (lpwp->hwnd, (LPPOINT)&lpwp->x); } } else if (wMsg == WM_GETMINMAXINFO) { if (!IsWindow(lpms->hWnd)) return; lStyle = GetWindowLong (lpms->hWnd, GWL_STYLE); if (lStyle & WS_THICKFRAME) sCyB = sCyFrame; else if (lStyle & WS_DLGFRAME) sCyB = sCyDlgFrame; else if (lStyle & WS_BORDER) sCyB = sCyBorder; CallNextHookEx (hCallHook, code, wParam, lParam); lpmm = (MINMAXINFO far *) lpms->lParam; lpmm->ptMaxSize.y = sMaxHeight + sCyB; GetWindowRect (lpms->hWnd, &rect); if (rect.bottom - rect.top + lpmm->ptMaxTrackSize.y > sMaxHeight) lpmm->ptMaxTrackSize.y = sMaxHeight + sCyB; return; } } CallNextHookEx (hCallHook, code, wParam, lParam); return; } //======================================================================== // Shell Hook function - Monitors for windows being created. When a // window is created, a message is posted to the main app. The app // then mods the default icon position to -2, -2 so that it can be // detected when the user minimizes it. //======================================================================== VOID FAR PASCAL ShellHookProc (INT code, WORD wParam, LONG lParam) { static char szTest[128]; if (code >= 0) { if (code == HSHELL_WINDOWCREATED) { GetWindowText ((HWND) wParam, szTest, sizeof (szTest)); if (lstrcmpi (szTest, "Task List") == 0) lpfnOldTaskWndProc = MySubClassWindow ((HWND) wParam, GetProcAddress (hInst, "TaskSCProc")); else if (hEXEWnd) PostMessage (hEXEWnd, MYMSG_SHELLNOTIFY, code, (LPARAM)wParam); } else if (code == HSHELL_WINDOWDESTROYED) { // Remove handle from icon pos array ComputeIconPos ((HWND) wParam, 0); } } CallNextHookEx (hShellHook, code, wParam, lParam); return; } //============================================================ // Task Manager window subclass procedure //============================================================ LONG CALLBACK TaskSCProc (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { // If the Arrange Icons button is clicked, redirect message. if ((wMsg == WM_COMMAND) && (wParam == 104)) { ArrangeIcons (); // Arrange the icons in our way. wParam = IDCANCEL; // Make Taskman go away. } return CallWindowProc (lpfnOldTaskWndProc, hWnd, wMsg, wParam, lParam); } //============================================================ // SetSetStatus - Exported routine that hooks or unhooks the // system hook routines //============================================================ UINT CALLBACK SetStatus (HWND hWnd, INT fFlag, INT cy) { hEXEWnd = hWnd; // Save bottom offset for icons sHeight = cy; // If not on top, use bottom of screen for maximize size if (fFlag & DFLAG_HIDEBAR) sMaxHeight = sCyDesk; else sMaxHeight = sCyDesk - cy; if (fFlag & DFLAG_HOOK) PILibHookCtl (TRUE); else PILibHookCtl (FALSE); return 0; } //============================================================ // ComputeNextIPos - Exported routine that returns the next // free icon position. //============================================================ void CALLBACK ComputeNextIPos (HWND hWnd, LPPOINT pt) { return ComputeIconPos (hWnd, pt); } //============================================================ // MyArrangeIcons - Exported routine that arranges the icons //============================================================ void CALLBACK MyArrangeIcons (void) { return ArrangeIcons (); } //----------------------------------------------------------- // PILibHookCtl - Controls setting/clearing system hooks // Hook, unhook // Start side: l,r,t or b //----------------------------------------------------------- INT PILibHookCtl (BOOL fHook) { INT sRC = 0; BOOL fFound = FALSE; //See if we need to hook the message queue if (fHook) { //Hook message loop if (hShellHook == 0) { hShellHook = SetWindowsHookEx (WH_SHELL, GetProcAddress (hInst, "ShellHookProc"), hInst, NULL); hCallHook = SetWindowsHookEx (WH_CALLWNDPROC, GetProcAddress (hInst, "MsgHookProc"), hInst, NULL); } } else { //Unhook message loop if (hShellHook) UnhookWindowsHookEx (hShellHook); if (hCallHook) UnhookWindowsHookEx (hCallHook); hShellHook = 0; hCallHook = 0; ArrangeIconicWindows (GetDesktopWindow()); } return sRC; } //----------------------------------------------------------- // ComputeIconPos - Computes the proper position of an icon //----------------------------------------------------------- void ComputeIconPos (HWND hWnd, LPPOINT pt) { static HWND hwndArray[MAXHANDLES]; static INT sMaxActive; INT sNum, sRow, sCol, sLineCnt; // If handle zero, init handle array if (hWnd == 0) { _fmemset (hwndArray, 0, sizeof (HWND) * MAXHANDLES); sMaxActive = 0; return; } // Find handle in array for (sNum = 0; sNum < sMaxActive; sNum++) if (hwndArray[sNum] == hWnd) break; // If point pointer zero, remove handle from the array if (pt == 0) { if (sNum < sMaxActive) hwndArray[sNum] = 0; return; } // if handle not found in array, find first free handle if (sNum == sMaxActive) { // Otherwise, find first free slot in array for (sNum = 0; sNum < MAXHANDLES; sNum++) if (hwndArray[sNum] == 0) break; if (sNum < MAXHANDLES) { hwndArray[sNum] = hWnd; if (sNum >= sMaxActive) sMaxActive++; } } // Now, compute position using the index computed above sLineCnt = (sCxDesk - sCxIcon) / sCxISpacing; sCol = sNum % sLineCnt; sRow = sNum / sLineCnt; pt->x = sCol * sCxISpacing + sCxISpacing/4; pt->y = sCyDesk - (sCyISpacing * sRow) - sCyISpacing - sHeight; return; } //----------------------------------------------------------- // ArrangeIcons - Arranges the icons on the desktop //----------------------------------------------------------- void ArrangeIcons (void) { WINDOWPLACEMENT wp; POINT pt; HWND hwndNext; LONG lStyle; wp.length = sizeof (wp); //First, move iconized windows. hwndNext = GetWindow (GetDesktopWindow(), GW_CHILD); while (hwndNext) { lStyle = GetWindowLong (hwndNext, GWL_STYLE); if ((lStyle & WS_VISIBLE) && !(lStyle & (WS_CHILD | WS_POPUP))) { if (IsIconic (hwndNext)) { GetWindowPlacement (hwndNext, &wp); //Set new icon position ComputeIconPos (hwndNext, &pt); wp.flags |= WPF_SETMINPOSITION; wp.ptMinPosition.x = pt.x; wp.ptMinPosition.y = pt.y; SetWindowPlacement (hwndNext, &wp); InvalidateRect (hwndNext, NULL, TRUE); } } hwndNext = GetWindow (hwndNext, GW_HWNDNEXT); } //Now remove iconic position for non-iconic windows. hwndNext = GetWindow (GetDesktopWindow(), GW_CHILD); while (hwndNext) { lStyle = GetWindowLong (hwndNext, GWL_STYLE); if ((lStyle & WS_VISIBLE) && !(lStyle & (WS_CHILD | WS_POPUP))) { if (!IsIconic (hwndNext)) { GetWindowPlacement (hwndNext, &wp); wp.ptMinPosition.x = -2; wp.ptMinPosition.y = -2; wp.flags |= WPF_SETMINPOSITION; SetWindowPlacement (hwndNext, &wp); } } hwndNext = GetWindow (hwndNext, GW_HWNDNEXT); } return; } //============================================================ // General helper routines //============================================================ //------------------------------------------------------------ // MySubClassWindow - Subclasses a window //------------------------------------------------------------ FARPROC MySubClassWindow (HWND hWnd, FARPROC lpfnNewProc) { FARPROC lpfnOldProc; lpfnOldProc = (FARPROC)GetWindowLong (hWnd, GWL_WNDPROC); SetWindowLong (hWnd, GWL_WNDPROC, (LONG) lpfnNewProc); return lpfnOldProc; }