MINOR: Change output filename
[openwide.git] / openwidedll.c
blobcc47f330e02de93e35f1354ea5c33b6e92aad7d7
1 /*
2 * Openwide -- control Windows common dialog
3 *
4 * Copyright (c) 2000 Luke Hudson
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include <windows.h>
23 #include <commctrl.h>
24 #include <shlwapi.h>
25 #include <shellapi.h>
26 #include <shlobj.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <dlgs.h>
30 #include "openwidedll.h"
31 #include "openwidedllres.h"
32 #include "owDllInc.h"
33 #include "owSharedUtil.h"
36 // DLL Instance handle
37 HINSTANCE ghInst = NULL;
39 // Handle to shared memory access locking mutex.
40 HANDLE ghMutex = NULL;
41 POWSharedData gpSharedMem = NULL; // pointer to shared mem
42 // Handle to filemapping for shared mem
43 HANDLE ghMap = NULL;
44 // System hook handles
45 HHOOK ghMsgHook = NULL, ghSysMsgHook = NULL;
47 // This cache is refreshed -- TODO: When?
48 OWSharedData gOwShared; // stores copy of shared mem for access to non-pointer datas without extended blocking
52 /* Add an icon to the toolbar within the O&S Dialogs
53 * @param hwTB -- toolbar handle
54 * @param hIcn -- icon handle
56 * @returns -1 on error, or the index of the new icon within the imagelist.
58 int addIcon2TB(HWND hwTB, HICON hIcn)
60 HIMAGELIST hImgList = NULL;
61 hImgList = (HIMAGELIST)SendMessage(hwTB, TB_GETIMAGELIST, 0, 0);
62 if (hImgList)
64 // int nImgs = ImageList_GetImageCount(hImgList);
65 int idxNew = ImageList_AddIcon(hImgList, hIcn);
66 if (idxNew == -1)
68 //dbg("%s, Error adding to imglist: %s", __func__, geterrmsg());
69 return -1;
71 else
73 //dbg("%s, Image added at index %d", __func__, idxNew);
74 SendMessage(hwTB, TB_SETIMAGELIST, 0, (LPARAM)hImgList);
75 return idxNew;
78 return -1;
82 * Adds a new button to the toolbar : hwnd
84 * @param hwnd -- parent window of toolbar, ie. the O&S Dialog.
86 * @returns 1 -- TODO: this should return 0 on error, but doesn't appear to.
88 static int addTBButton(HWND hwnd)
90 // Locate the toolbar handle.
91 HWND hwTB = findChildWindow(hwnd, CID_TOOLBAR, TOOLBARCLASSNAME);
93 // Create toolbar button structure
94 TBBUTTON tb = { 0 };
95 tb.iBitmap = VIEW_NETCONNECT;
97 // Load the toolbar icon, and add it to the imagelist, retaining the index.
98 int idxNew = -1;
99 HICON hIcn = (HICON)LoadImage(ghInst, MAKEINTRESOURCE(IDI_TBICON), IMAGE_ICON, 16, 16, 0);
100 if (hIcn)
102 idxNew = addIcon2TB(hwTB, hIcn);
103 DestroyIcon(hIcn);
105 if (idxNew >= 0)
106 tb.iBitmap = idxNew; // set button image index
107 tb.idCommand = OW_TBUTTON_CMDID; // set command id -- @see openwidedll.h
108 // Set the button style flags
109 tb.fsStyle = BTNS_AUTOSIZE | BTNS_BUTTON | BTNS_SHOWTEXT | BTNS_DROPDOWN; // BTNS_WHOLEDROPDOWN;
110 // Set the button state flags
111 tb.fsState = TBSTATE_ENABLED;
112 // And give it a tooltip ? TODO: Check this
113 tb.iString = (INT_PTR)"OpenWide by Lingo";
114 // Add the button.
115 SendMessage(hwTB, TB_ADDBUTTONS, 1, (LPARAM) & tb);
117 // Ensure that the toolbar window is large enough to show the new button.
118 RECT r;
119 int idxLast = SendMessage(hwTB, TB_BUTTONCOUNT, 0, 0) - 1;
120 if (SendMessage(hwTB, TB_GETITEMRECT, idxLast, (LPARAM) & r))
122 RECT rw;
123 GetWindowRect(hwTB, &rw);
124 MapWindowPoints(hwTB, NULL, (LPPOINT) & r, 2);
125 SetWindowPos(hwTB, NULL, 0, 0, (r.right + 8) - rw.left, rw.bottom - rw.top + 1, SWP_NOMOVE | SWP_NOZORDER);
127 return 1;
128 } // END of addTBButton(...)
131 * Show a drop-down menu from the toolbar button.
133 * @param hwnd -- O&S dialog
134 * @param hwTB -- toolbar handle
135 * @param uiItem -- id of toolbar item ? -- TODO: Check this.
137 static void dropMenu(HWND hwnd, HWND hwTB, UINT uiItem)
139 RECT r;
140 // Get the screen coords rectangle of the button
141 SendMessage(hwTB, TB_GETRECT, uiItem, (LPARAM) & r);
142 MapWindowPoints(hwTB, NULL, (LPPOINT) & r, 2);
144 // Set the area for the menu to avoid. ? :: TODO: see Platform SDK on TrackPopupMenuEx
145 TPMPARAMS tpm = { 0 };
146 tpm.cbSize = sizeof(tpm);
147 tpm.rcExclude = r;
149 // Create the menu structure.
150 HMENU hm = CreatePopupMenu();
151 AppendMenu(hm, MF_STRING, OW_EXPLORE_CMDID, "&Locate current folder with Explorer...");
152 AppendMenu(hm, MF_STRING, OW_SHOWDESK_CMDID, "Show &Desktop [for Gabriel]...");
153 AppendMenu(hm, MF_SEPARATOR | MF_DISABLED, 0, NULL);
154 AppendMenu(hm, MF_STRING, OW_ABOUT_CMDID, "&About OpenWide...");
155 SetMenuDefaultItem(hm, OW_SHOWDESK_CMDID, FALSE);
157 // * This section is todo with having Favourite directories, and is unfinished.
159 AppendMenu(hm, MF_STRING, OW_ADDFAV_CMDID, "Add &Favourite");
160 SetMenuDefaultItem(hm, OW_ADDFAV_CMDID, FALSE);
161 POWSharedData pow = lockSharedData();
162 if (pow)
164 dbg("%s, Locked shared data ok", __func__);
165 PFavLink pFav = pow->pFaves;
166 if (pFav)
168 MENUITEMINFO mii = { 0 };
169 mii.cbSize = sizeof(mii);
170 AppendMenu(hm, MF_SEPARATOR | MF_DISABLED, 0, NULL);
171 for (int i = 0; i < pow->nFaves; i++)
173 pFav = getNthFave(pow, i);
174 if (!pFav)
175 break;
176 static char szBuf[MAX_PATH + 8];
178 dbgLink("inserting...", pFav);
179 mii.fMask = MIIM_STRING | MIIM_DATA | MIIM_ID;
180 mii.fType = MFT_STRING;
181 wsprintf(szBuf, "%s\tCtrl+%d", pFav->szFav, (pFav->idCmd - OW_FAVOURITE_CMDID) + 1);
182 mii.dwTypeData = szBuf;
183 mii.dwItemData = pFav->idCmd;
184 mii.wID = pFav->idCmd;
186 int iRes = InsertMenuItem(hm, -1, TRUE, &mii);
187 if (iRes == 0)
188 dbg("%s, Failed inserting item: %s", __func__, geterrmsg());
189 //idx = AppendMenu(hm, MF_STRING, iCmd++, pFav->szFav);
192 unlockSharedData(pow);
195 // Display, track, then destroy the menu.
196 TrackPopupMenuEx(hm, TPM_HORIZONTAL | TPM_RIGHTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL, r.right, r.bottom, hwnd, &tpm);
197 DestroyMenu(hm);
198 } // END of dropMenu(...)
202 // add a new 'place' into the Places bar.
203 int addPlace(HWND hwnd, PFavLink plk)
205 HWND hwTB = GetDlgItem(hwnd, CID_PLACES);
207 TBBUTTON tb = { 0 };
208 tb.iBitmap = giPlacesIcon;
209 tb.idCommand = plk->idCmd;
210 tb.fsStyle = BTNS_BUTTON | BTNS_SHOWTEXT; // BTNS_WHOLEDROPDOWN;
211 tb.fsState = TBSTATE_ENABLED;
212 tb.iString = (INT_PTR)PathFindFileName(plk->szFav);
213 SendMessage(hwTB, TB_ADDBUTTONS, 1, (LPARAM) & tb);
214 return 1;
218 // Add a new favourite dir, first retrieving the path from the current view of the O&S dialog.
219 // *unfinished*
220 int addFavourite(HWND hwnd)
222 //static char szBuf[2*MAX_PATH+1];
223 assert( IsWindow(hwnd));
225 char *szBuf = (char *)GlobalAlloc(GPTR, 2 * MAX_PATH + 1);
226 if( !szBuf )
227 return 0;
228 if( SendMessage(hwnd, CDM_GETFOLDERPATH, 2*MAX_PATH, (LPARAM)szBuf) > 0 )
230 if( !faveExists(szBuf) )
232 PFavLink plNew = newFav(szBuf);
233 if( plNew )
234 addPlace(hwnd, plNew);
235 else
236 dbg("%s, failed to create new fave", __func__);
238 else
239 dbg("%s, Fave: '%s' exists already", __func__, szBuf);
240 return 1;
242 GlobalFree(szBuf);
243 return 0;
248 * Given the handle to the O&S dialog, this does the magic to it, such as
249 * adding toolbar buttons, setting the focus and view mode, and adding items to
250 * the system menu.
252 * @returns 1, TODO:: There should be error indication, perhaps!
254 int openWide(HWND hwnd)
256 // set placement
257 int w = gOwShared.szDim.cx;
258 int h = gOwShared.szDim.cy;
259 int x = gOwShared.ptOrg.x;
260 int y = gOwShared.ptOrg.y;
261 SetWindowPos(hwnd, NULL, x, y, w, h, SWP_NOZORDER);
263 // set view mode
264 HWND hwDirCtl = GetDlgItem(hwnd, CID_DIRLISTPARENT);
265 WORD vCmdID = viewToCmdID(gOwShared.iView);
266 // set the view mode, by sending a fake command message.
267 SendMessage(hwDirCtl, WM_COMMAND, MAKEWPARAM(vCmdID, 0), 0);
269 // set the focus!
270 focusDlgItem(hwnd, gOwShared.iFocus);
272 #ifdef HOOK_SYSMSG
273 // debug hook, to find menu cmd IDs
274 dbg("Hooking SYSMSG...");
275 ghSysMsgHook = SetWindowsHookEx(
276 WH_SYSMSGFILTER,
277 SysMsgProc,
278 ghInst,
279 0 //GetCurrentThreadId() // Only install for THIS thread!!!
281 dbg("Hooking returned %p", ghSysMsgHook);
282 #endif
283 // Allow drag&drop onto window. Unfortunately this doesn't work for the
284 // directory list, as that is already set to accept drops, as a command to
285 // copy/move files. I would have to subclass this too, and that's rather
286 // more complicated.
287 DragAcceptFiles(hwnd, TRUE);
289 // Insert item into the system menu (right-click on titlebar)
290 HMENU hm = GetSystemMenu(hwnd, FALSE);
291 AppendMenu(hm, MF_SEPARATOR | MF_DISABLED, 0, NULL);
292 AppendMenu(hm, MF_STRING, OW_EXPLORE_CMDID, "&Locate current folder with Explorer...");
293 AppendMenu(hm, MF_STRING, OW_ABOUT_CMDID, "&About OpenWide...");
295 addTBButton(hwnd); // add the toolbar button.
297 // Modify the dir-list view flags
298 HWND hwShellCtl = GetDlgItem(hwnd, CID_DIRLISTPARENT);
299 hwShellCtl = GetDlgItem(hwShellCtl, 1);
300 ListView_SetExtendedListViewStyleEx(hwShellCtl, OW_LISTVIEW_STYLE, OW_LISTVIEW_STYLE );
302 return 1;
303 } // END openWide(...)
306 /* Load the desktop folder into the dir list */
307 void showDesktop(HWND hwnd)
309 char * szDesk = GlobalAlloc(GPTR, MAX_PATH+1);
310 if( szDesk && SHGetSpecialFolderPath(hwnd, szDesk, CSIDL_DESKTOPDIRECTORY,FALSE) )
312 char *szOld = getDlgItemText(hwnd, CID_FNAME);
313 SetDlgItemText(hwnd, CID_FNAME, szDesk);
314 SendDlgItemMessage(hwnd, CID_FNAME, EM_SETSEL, -1, -1);
315 SendDlgItemMessage(hwnd, CID_FNAME, EM_REPLACESEL, FALSE, (LPARAM)"\\");
316 SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDOK, BN_CLICKED), (LPARAM)GetDlgItem(hwnd, IDOK));
317 if( szOld )
318 SetDlgItemText(hwnd, CID_FNAME, szOld);
319 else
320 SetDlgItemText(hwnd, CID_FNAME, "");
321 free(szOld);
322 GlobalFree(szDesk);
324 } // END showDesktop
328 * This is the callback for the subclassed O&S dialog window, and it handles
329 * all the extra functionality, passing along messages to the old callback
330 * function unless the behaviour is modified.
333 LRESULT CALLBACK WINAPI wpSubMain(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
335 /* if( gbDbg )
337 dbgWM(hwnd, msg, wp, lp);
340 // retrieve a ptr to the extra information associated with the window.
341 POWSubClassData pow = (POWSubClassData)GetProp(hwnd, OW_PROP_NAME);
342 if( !pow )
343 return DefWindowProc(hwnd, msg, wp, lp); // something's broken, so just allow default window function.
345 static char buffer[MAX_PATH+1];
347 switch(msg)
349 case WM_INITDIALOG:
351 // dbg("DLL: INITDIALOG");
352 LRESULT lRes = CallWindowProc(pow->wpOrig, hwnd, msg, wp, lp); // call the old callback
353 ShowWindow(hwnd, SW_HIDE); // hide the window, until it's been magick-ed by openWide(...)
354 return lRes;
356 break;
358 case WM_SHOWWINDOW:
359 if( wp && !pow->bSet ) // catch the first SHOWWINDOW only,
361 pow->bSet = TRUE;
362 openWide(hwnd);
364 break;
366 case WM_COMMAND: // handle custom toolbar button commands, etc.
367 switch (LOWORD(wp))
369 case OW_ABOUT_CMDID: // about
370 MessageBox(hwnd, "OpenWide is written by Luke Hudson. (c)2005", "About OpenWide", MB_OK);
371 return 0;
372 // show desktop item, or click on button rather than
373 // dropdown (ie, defaults to show desktop menuitem)
374 case OW_TBUTTON_CMDID:
375 case OW_SHOWDESK_CMDID:
376 showDesktop(hwnd);
377 break;
378 case OW_EXPLORE_CMDID: // Explore current dir in new Explorer window
380 // Build a command line
381 char *szParm = "/select,";
382 wsprintf(buffer, szParm);
383 int len = strlen(szParm);
384 LPARAM lpBuf = (LPARAM)buffer + (LPARAM)len;
385 //dbg("CDM_GET..PATH, cbSize=%d, buffer = %p", MAX_PATH-len, lpBuf);
386 len = SendMessage(hwnd, CDM_GETFOLDERPATH, MAX_PATH - len, lpBuf); //(LPARAM)(char *)((unsigned int)buffer + (unsigned int)len));
387 if (len)
389 // execute the command line
390 ShellExecute(hwnd, NULL, "explorer.exe", buffer, NULL, SW_SHOWNORMAL);
392 } // case
393 return 0;
395 // Handling of favourites -- UNFININSHED
396 case OW_ADDFAV_CMDID:
397 doAddFave(hwnd);
398 return 0;
399 default:
400 if (LOWORD(wp) >= OW_FAVOURITE_CMDID)
402 getFavourite(hwnd, (int)LOWORD(wp));
404 break;*/
405 } // switch : command ids
406 break;
408 // Handle notifications from the toolbar
409 case WM_NOTIFY:
411 NMHDR *phdr = (NMHDR *)lp;
412 HWND hwTB = findChildWindow(hwnd, CID_TOOLBAR, TOOLBARCLASSNAME);
413 if (phdr->hwndFrom == hwTB)
415 // dbg("Got notify %d from toolbar", phdr->code);
416 if (phdr->code == TBN_DROPDOWN)
418 NMTOOLBAR *ptb = (NMTOOLBAR *)lp;
419 if (ptb->iItem == OW_TBUTTON_CMDID)
421 dropMenu(hwnd, hwTB, ptb->iItem);
422 return TBDDRET_DEFAULT;
427 break;
429 // handle notifications from the dir listview control
430 case WM_PARENTNOTIFY:
431 if( LOWORD(wp) == WM_CREATE)
433 static char buf[33];
434 GetClassName((HWND)lp, buf, 32);
436 if( strcmp(buf, "SHELLDLL_DefView") == 0 )
438 // dbg("Shell defview ctl created");
439 // subclass((HWND)lp, wpSubShellCtl, (LPARAM)hwnd);
440 HWND hwLV = GetDlgItem((HWND)lp, 1);
441 if( hwLV )
443 if( GetWindowLong(hwLV, GWL_STYLE) & LVS_REPORT ) // if details view is in effect.
445 // update style flags
446 ListView_SetExtendedListViewStyleEx(hwLV, OW_LISTVIEW_STYLE, OW_LISTVIEW_STYLE );
447 // Send Control+NumpadPlus to expand all the columns to fit contents
448 INPUT in[4] = {0};
449 in[0].type = INPUT_KEYBOARD;
450 in[0].ki.wVk = VK_CONTROL;
451 in[1].type = INPUT_KEYBOARD;
452 in[1].ki.wVk = VK_ADD;
453 in[2].type = INPUT_KEYBOARD;
454 in[2].ki.wVk = VK_CONTROL;
455 in[2].ki.dwFlags = KEYEVENTF_KEYUP;
456 in[3].type = INPUT_KEYBOARD;
457 in[3].ki.wVk = VK_ADD;
458 in[3].ki.dwFlags = KEYEVENTF_KEYUP;
459 HWND hwOld = SetFocus(hwLV);
460 SendInput(4, in, sizeof(INPUT));
461 SetFocus(hwOld);
464 //SetTimer(hwnd, 251177, 1, NULL); // set a timer, for what? TODO:: Check this
467 break;
468 /// Deprecated -- I think? TODO: Check
469 /* case WM_TIMER:
470 if( wp == 251177 )
472 KillTimer(hwnd, 251177);
473 HWND hwDirCtl = GetDlgItem(hwnd, CID_DIRLISTPARENT);
474 if( getSharedData() )
476 if( gOwShared.iView == V_THUMBS || gOwShared.iView == V_TILES )
478 // dbg("posting cmd message to reset view?");
479 WORD vCmdID = viewToCmdID(gOwShared.iView);
480 PostMessage(hwDirCtl, WM_COMMAND, MAKEWPARAM(vCmdID, 0), 0);
484 break;
486 case WM_SYSCOMMAND: // Handle system menu commands
488 int cmdId = wp & 0xFFF0;
489 if( cmdId == OW_ABOUT_CMDID )
491 MessageBox(hwnd, "OpenWide is written by Luke Hudson. (c)2005", "About OpenWide", MB_OK);
492 return 0;
494 else if( cmdId == OW_EXPLORE_CMDID )
496 char * szParm = "/select,";
497 wsprintf(buffer, szParm);
498 int len = strlen(szParm);
499 len = SendMessage(hwnd, CDM_GETFOLDERPATH, MAX_PATH-len, (LPARAM)(buffer+len));
500 if( len )
502 ShellExecute(hwnd, NULL, "explorer.exe", buffer, NULL, SW_SHOWNORMAL);
506 break;
507 /* case WM_NCPAINT: // handle painting of non-content area, ie. window titlebar and frame.
509 HDC hdc = GetWindowDC(hwnd);
510 HBRUSH hbrOld;
511 HPEN hpOld;
512 hbrOld = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
513 hpOld = SelectObject(hdc, GetStockObject(NULL_PEN));
514 RECT r;
515 GetWindowRect(hwnd, &r);
516 r.right-=r.left;
517 r.left -= r.left;
518 r.bottom-=r.top;
519 r.top -= r.top;
520 RoundRect(hdc, r.left, r.top, r.right, r.bottom, 16,16);
521 SelectObject(hdc, hbrOld);
522 SelectObject(hdc, hpOld);
523 ReleaseDC(hwnd, hdc);
525 break;*/
526 case WM_DROPFILES: // Handle files which are dragged&dropped onto window.
528 HANDLE hDrop = (HANDLE)wp;
529 int nFiles = DragQueryFile(hDrop, (UINT)-1, NULL, 0);
530 if( nFiles == 1 )
532 if( DragQueryFile(hDrop, 0, buffer, MAX_PATH) )
534 if( PathIsDirectory(buffer) )
536 // Set the view to dropped directory path.
537 SetDlgItemText(hwnd, CID_FNAME, buffer);
538 SendDlgItemMessage(hwnd, CID_FNAME, EM_SETSEL, -1, -1);
539 SendDlgItemMessage(hwnd, CID_FNAME, EM_REPLACESEL, FALSE, (LPARAM)"\\");
540 SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDOK, BN_CLICKED), (LPARAM)GetDlgItem(hwnd, IDOK));
541 SetDlgItemText(hwnd, CID_FNAME, "");
542 if( getSharedData() )
544 focusDlgItem(hwnd, gOwShared.iFocus);
550 return 0;
551 case WM_DESTROY:
553 //dbg("DLL: DESTROY");
554 if( openSharedMem() )
556 //dbg("DLL: Opened shared memory");
557 if( --gpSharedMem->refCount < 0 ) // Update the count for number of users of subclass code
558 gpSharedMem->refCount = 0;
559 //dbg("DLL: dec'd refCount to %d, posting msg %x to app window %p", gpSharedMem->refCount,
560 // gpSharedMem->iCloseMsg, gpSharedMem->hwListener);
562 // Notify application that another O&S dialog has closed
563 PostMessage( gpSharedMem->hwListener, gpSharedMem->iCloseMsg, 0,0);
564 // Release any hold on the shared memory.
565 closeSharedMem();
567 // Remove subclassing
568 WNDPROC wpOrig = pow->wpOrig;
569 unsubclass(hwnd);
570 // Call original WM_DESTROY
571 return CallWindowProc(wpOrig, hwnd, msg, wp, lp);
573 break;
575 return CallWindowProc(pow->wpOrig, hwnd, msg, wp, lp);
576 } // END wpSubMain
579 // Subclass the listview control -- TODO: I think this is un-needed
580 LRESULT CALLBACK WINAPI wpSubShellCtl(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
582 POWSubClassData pow = (POWSubClassData)GetProp(hwnd, OW_PROP_NAME);
583 if( !pow )
584 return DefWindowProc(hwnd, msg, wp, lp);
586 switch(msg)
588 case WM_DROPFILES:
590 HANDLE hDrop = (HANDLE)wp;
591 int nFiles = DragQueryFile(hDrop, (UINT)-1, NULL, 0);
592 ////dbg("%d files dropped, fwding mesg to %p", nFiles, pow->lpData);
593 return SendMessage((HWND)pow->lpData, msg, wp, lp);
595 break;
596 case WM_DESTROY:
598 WNDPROC wpOrig = pow->wpOrig;
599 unsubclass(hwnd);
600 //dbg("SHell view being destroyed");
601 return CallWindowProc(wpOrig, hwnd, msg, wp, lp);
603 break;
605 return CallWindowProc(pow->wpOrig, hwnd, msg, wp, lp);
606 } // END wpSubShellCtl
609 /* Check whether this application has been excluded, ie, whether we should not
610 * mess with its O&S dialogs
612 static BOOL isExcluded(const char *szApp)
614 BOOL bEx = FALSE;
615 HKEY hk = regOpenKey(HKEY_CURRENT_USER, OW_REGKEY_EXCLUDES_NAME);
616 if( hk )
618 regGetDWORD(hk, szApp, &bEx);
619 regCloseKey(hk);
621 return bEx;
626 * Investigate the WM_CREATEPARAMS message
628 static void dbgCreateParams(LPVOID lpCreateParams)
630 UNALIGNED short * pcbData = (UNALIGNED short *)lpCreateParams;
631 if( pcbData )
633 short cbData = * pcbData;
634 UNALIGNED byte *pbData = (UNALIGNED byte *)pcbData;
635 pbData += sizeof(short);
636 dbg("**CreateParams:");
637 dbg(" %d bytes of data, starting at x%p", cbData, pbData);
638 if( pbData )
640 dbg(" First 8 bytes follow:");
641 int len = min( cbData, 8 );
642 char s[32] = {0};
643 int i;
644 for(i=0; i < len; i++)
646 s[i] = pbData[i];
648 s[i] = 0;
649 dbg(" \"%s\" (hex follows)", s);
650 char st[8];
651 s[0] = 0;
652 for(i=0; i < len; i++)
654 sprintf(st, "%02x ", pbData[i]);
655 strcat(s, st);
657 dbg(" %s", s);
660 else
661 dbg("CreateParams is NULL (%p)", pcbData);
666 * This is the main hook callback, which watches window creation, and
667 * subclasses those which appear (with luck, correctly) to be O&S dialogs */
668 static LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
671 if(nCode < 0)
673 if( ghMsgHook )
674 return CallNextHookEx(ghMsgHook, nCode, wParam, lParam);
677 switch(nCode)
679 case HCBT_CREATEWND:
681 static char buf[256];
682 HWND hwNew = (HWND)wParam;
683 CBT_CREATEWND * pcw = (CBT_CREATEWND *)lParam;
684 CREATESTRUCT * pcs = (CREATESTRUCT*) pcw->lpcs;
686 if( GetClassName(hwNew, buf, 255) && pcs->lpszName )
688 DWORD style = (DWORD)GetWindowLong(hwNew, GWL_STYLE);
689 DWORD exStyle = (DWORD)GetWindowLong(hwNew, GWL_EXSTYLE);
691 if (strcmp(buf, "#32770") != 0 || strcmp(pcs->lpszName, "Open") != 0)
693 break;
696 if( (style == OW_MATCH_STYLE && exStyle == OW_MATCH_EXSTYLE)
697 || (style == OW_MATCH_STYLE_W7 && exStyle == OW_MATCH_EXSTYLE_W7))
699 BOOL bTakeOver = TRUE;
701 //// FIND name of Calling app ////
702 char *szApp = malloc( MAX_PATH+1 );
703 if( szApp && GetModuleFileName(NULL, szApp, MAX_PATH) )
705 if( isExcluded(szApp) )
706 bTakeOver = FALSE;
707 //dbg("DLL: Module: %s", szApp);
708 free(szApp);
711 ///dbg("DLL: Found O&S dlg %p, attempting access to shared mem", hwNew);
713 if( bTakeOver && openSharedMem() )
715 //dbgCreateParams(pcs->lpCreateParams);
716 //dbg("DLL: Opened shared memory");
717 if( gpSharedMem->bDisable )
718 bTakeOver = FALSE;
719 else
720 gpSharedMem->refCount++;
721 //dbg("DLL: Inc'd refCount to %d", gpSharedMem->refCount);
722 closeSharedMem();
723 //dbg("DLL: Closed shared memory");
725 if( bTakeOver )
727 pcs->style &= ~WS_VISIBLE;
728 ShowWindow(hwNew, SW_HIDE);
729 subclass(hwNew, wpSubMain, 0);
734 return 0;
736 // Call the next hook, if there is one
737 return CallNextHookEx(ghMsgHook, nCode, wParam, lParam);
738 } // END CBTProc
741 * Access to shared memory, and copy data to cache
743 int openSharedMem(void)
745 if( ghMap != NULL || gpSharedMem != NULL )
746 return 1;
748 if(!waitForMutex())
749 return 0;
751 ghMap = OpenFileMapping(FILE_MAP_WRITE, FALSE, OW_SHARED_FILE_MAPPING);
752 if( ghMap )
754 gpSharedMem = (POWSharedData)MapViewOfFile(ghMap, FILE_MAP_WRITE, 0,0, 0);
755 if( gpSharedMem )
757 CopyMemory(&gOwShared, gpSharedMem, sizeof(OWSharedData));
758 return 1;
760 else
761 closeSharedMem();
763 return 0;
764 } // END openSharedMem
767 * Release any access to shared memory we may hold.
769 void closeSharedMem(void)
771 if( gpSharedMem )
773 UnmapViewOfFile(gpSharedMem);
774 gpSharedMem = NULL;
776 if( ghMap )
778 CloseHandle(ghMap);
779 ghMap = NULL;
781 releaseMutex();
782 } // END closeSharedMem
786 * Simply refreshes our cache of the shared data.
787 * Use this as a preference to the open/close-SharedMem functions.
789 * @returns 1 if successful, 0 on error.
791 int getSharedData(void)
793 int rv = 0;
794 if( openSharedMem() )
796 rv = 1;
797 closeSharedMem();
799 return rv;
804 * exported function to setup the CBT hook, which watches window creation.
806 int DLLEXPORT setHook(void)
808 if(ghMsgHook != NULL)
810 //SendMessage(gOwShared.hwLog, LB_ADDSTRING, 0, (LPARAM)"Already hooked");
811 return 1;
813 if(!getSharedData())
815 // SendMessage(hwLB, LB_ADDSTRING, 0, (LPARAM)"Failed to get shared data!!!");
816 // dbg("Hook failed to get shared mems");
817 return FALSE;
819 //SendMessage(gOwShared.hwLog, LB_ADDSTRING, 0, (LPARAM)"Setting hook....");
820 ghMsgHook = SetWindowsHookEx(WH_CBT, CBTProc, ghInst, 0);
821 if(ghMsgHook != NULL)
823 //dbg("Hooked okay");
824 //SendMessage(gOwShared.hwLog, LB_ADDSTRING, 0, (LPARAM)"Hooked ok!");
825 return 1;
827 //dbg("Hook failed");
828 //SendMessage(gOwShared.hwLog, LB_ADDSTRING, 0, (LPARAM)"Failed hook");
829 return 0;
834 * Exported function to remove the CBT hook.
836 int DLLEXPORT rmvHook(void)
838 if( !ghMsgHook )
839 return 1;
841 if( ghSysMsgHook )
843 UnhookWindowsHookEx(ghSysMsgHook);
844 ghSysMsgHook = NULL;
846 //dbg("DLL: Removing hook");
847 if( ghMsgHook )
849 UnhookWindowsHookEx(ghMsgHook);
850 ghMsgHook = NULL;
852 //dbg("DLL: removed hook okay");
853 return 1;
859 // This callback handles SYSMSG hooks, which I have used to investigate the O&S dialog behaviour.
861 static LRESULT CALLBACK SysMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
863 HWND hwnd;
865 if(nCode < 0)
866 return CallNextHookEx(ghMsgHook, nCode, wParam, lParam);
868 LPMSG pMsg = (MSG *)lParam;
869 if( GetAsyncKeyState(VK_SHIFT) & 0x8000 )
871 LRESULT lRet = CallNextHookEx(ghSysMsgHook, nCode, wParam, lParam);
872 UnhookWindowsHookEx(ghSysMsgHook);
873 ghSysMsgHook = NULL;
874 return lRet;
876 switch(pMsg->message)
878 case WM_TIMER:
879 case WM_PAINT:
880 break;
881 case WM_MENUSELECT:
883 dbg("WM_MENUSELECT: %p %d", pMsg->hwnd, LOWORD(pMsg->wParam));
885 HMENU hm = (HMENU)pMsg->lParam;
886 if(hm)
888 static char buf[80];
889 MENUITEMINFO mii ={0};
890 int nItems = GetMenuItemCount(hm);
891 dbg(" %d items in menu", nItems);
892 for(int i=0; i < nItems; i++)
894 mii.cbSize = sizeof(mii);
895 mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
896 mii.cch = 79;
897 mii.dwTypeData = (LPTSTR)buf;
898 GetMenuItemInfo(hm, i, TRUE, &mii);
899 dbg(" Item %d: %.8s, %d", i, buf, mii.wID);
903 UnhookWindowsHookEx(ghSysMsgHook);
904 ghSysMsgHook = NULL;
906 break;
907 default:
908 if (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST) {
909 dbg("SysMsgProc: %d is code, pMsg: hwnd: %p, message: %d, wp: %x, lp: %x", nCode, pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam);
911 break;
913 // Call the next hook, if there is one
914 return CallNextHookEx(ghSysMsgHook, nCode, wParam, lParam);
921 * Main DLL entry point
923 BOOL DLLEXPORT WINAPI DLLPROC(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
925 switch (fdwReason)
927 case DLL_PROCESS_ATTACH:
928 ghInst = hDLLInst;
929 break;
930 case DLL_PROCESS_DETACH:
931 ghInst = NULL;
932 break;
933 default:
934 break;
936 return TRUE;