2 * Open With Context Menu extension
4 * Copyright 2007 Johannes Anderwald <janderwald@reactos.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 WINE_DEFAULT_DEBUG_CHANNEL (shell
);
26 /// [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system]
27 /// "NoInternetOpenWith"=dword:00000001
31 // implement duplicate checks in list box
32 // implement duplicate checks for MRU!
33 // implement owner drawn menu
37 const IContextMenu2Vtbl
*lpVtblContextMenu
;
38 const IShellExtInitVtbl
*lpvtblShellExtInit
;
43 WCHAR szPath
[MAX_PATH
];
45 } SHEOWImpl
, *LPSHEOWImpl
;
55 }OPEN_WITH_CONTEXT
, *POPEN_WITH_CONTEXT
;
57 #define MANUFACTURER_NAME_SIZE 100
62 WCHAR szAppName
[MAX_PATH
];
63 WCHAR szManufacturer
[MANUFACTURER_NAME_SIZE
];
64 }OPEN_ITEM_CONTEXT
, *POPEN_ITEM_CONTEXT
;
67 typedef struct _LANGANDCODEPAGE_
71 } LANGANDCODEPAGE
, *LPLANGANDCODEPAGE
;
80 } MRUINFO
, *LPMRUINFO
;
82 #define MRUF_STRING_LIST 0
84 typedef HANDLE (WINAPI
*CREATEMRULISTPROCW
)(
88 typedef int (WINAPI
*ENUMMRULISTW
)(
95 typedef int (WINAPI
*ADDMRUSTRINGW
)(
100 typedef void (WINAPI
*FREEMRULIST
)(
103 static const IShellExtInitVtbl eivt
;
104 static const IContextMenu2Vtbl cmvt
;
105 static HRESULT WINAPI
SHEOWCm_fnQueryInterface(IContextMenu2
*iface
, REFIID riid
, LPVOID
*ppvObj
);
106 static ULONG WINAPI
SHEOWCm_fnRelease(IContextMenu2
*iface
);
108 HANDLE
OpenMRUList(HKEY hKey
);
109 void LoadItemFromHKCU(POPEN_WITH_CONTEXT pContext
, WCHAR
* szExt
);
110 void LoadItemFromHKCR(POPEN_WITH_CONTEXT pContext
, WCHAR
* szExt
);
111 void InsertOpenWithItem(POPEN_WITH_CONTEXT pContext
, WCHAR
* szAppName
);
113 static HMODULE hModule
= NULL
;
114 static CREATEMRULISTPROCW CreateMRUListProcW
= NULL
;
115 static ENUMMRULISTW EnumMRUListW
= NULL
;
116 static FREEMRULIST FreeMRUListProc
= NULL
;
117 static ADDMRUSTRINGW AddMRUStringW
= NULL
;
120 HRESULT WINAPI
SHEOW_Constructor(IUnknown
* pUnkOuter
, REFIID riid
, LPVOID
*ppv
)
125 ow
= LocalAlloc(LMEM_ZEROINIT
, sizeof(SHEOWImpl
));
128 return E_OUTOFMEMORY
;
132 ow
->lpVtblContextMenu
= &cmvt
;
133 ow
->lpvtblShellExtInit
= &eivt
;
135 TRACE("(%p)->()\n",ow
);
137 res
= SHEOWCm_fnQueryInterface( (IContextMenu2
*)&ow
->lpVtblContextMenu
, riid
, ppv
);
138 SHEOWCm_fnRelease( (IContextMenu2
*)&ow
->lpVtblContextMenu
);
142 static LPSHEOWImpl __inline
impl_from_IShellExtInit( IShellExtInit
*iface
)
144 return (SHEOWImpl
*)((char*)iface
- FIELD_OFFSET(SHEOWImpl
, lpvtblShellExtInit
));
147 static LPSHEOWImpl __inline
impl_from_IContextMenu( IContextMenu2
*iface
)
149 return (SHEOWImpl
*)((char*)iface
- FIELD_OFFSET(SHEOWImpl
, lpVtblContextMenu
));
152 static HRESULT WINAPI
SHEOWCm_fnQueryInterface(IContextMenu2
*iface
, REFIID riid
, LPVOID
*ppvObj
)
154 SHEOWImpl
*This
= impl_from_IContextMenu(iface
);
156 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This
,debugstr_guid(riid
),ppvObj
);
160 if(IsEqualIID(riid
, &IID_IUnknown
) ||
161 IsEqualIID(riid
, &IID_IContextMenu
) ||
162 IsEqualIID(riid
, &IID_IContextMenu2
))
164 *ppvObj
= (void *)&This
->lpVtblContextMenu
;
166 else if(IsEqualIID(riid
, &IID_IShellExtInit
))
168 *ppvObj
= (void *)&This
->lpvtblShellExtInit
;
173 IUnknown_AddRef((IUnknown
*)*ppvObj
);
174 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
177 TRACE("-- Interface: E_NOINTERFACE\n");
178 return E_NOINTERFACE
;
181 static ULONG WINAPI
SHEOWCm_fnAddRef(IContextMenu2
*iface
)
183 SHEOWImpl
*This
= impl_from_IContextMenu(iface
);
184 ULONG refCount
= InterlockedIncrement(&This
->ref
);
186 TRACE("(%p)->(count=%u)\n", This
, refCount
- 1);
191 static ULONG WINAPI
SHEOWCm_fnRelease(IContextMenu2
*iface
)
193 SHEOWImpl
*This
= impl_from_IContextMenu(iface
);
194 ULONG refCount
= InterlockedDecrement(&This
->ref
);
196 TRACE("(%p)->(count=%i)\n", This
, refCount
+ 1);
200 TRACE(" destroying IContextMenu(%p)\n",This
);
201 HeapFree(GetProcessHeap(),0,This
);
207 AddItem(HMENU hMenu
, UINT idCmdFirst
)
210 WCHAR szBuffer
[MAX_PATH
];
211 static const WCHAR szChoose
[] = { 'C','h','o','o','s','e',' ','P','r','o','g','r','a','m','.','.','.',0 };
213 ZeroMemory(&mii
, sizeof(mii
));
214 mii
.cbSize
= sizeof(mii
);
215 mii
.fMask
= MIIM_TYPE
| MIIM_ID
;
216 mii
.fType
= MFT_SEPARATOR
;
218 InsertMenuItemW(hMenu
, -1, TRUE
, &mii
);
220 if (!LoadStringW(shell32_hInstance
, IDS_OPEN_WITH_CHOOSE
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
)))
221 wcscpy(szBuffer
, szChoose
);
223 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
225 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
226 mii
.fType
= MFT_STRING
;
227 mii
.fState
= MFS_ENABLED
;
228 mii
.wID
= idCmdFirst
;
229 mii
.dwTypeData
= (LPWSTR
)szBuffer
;
230 mii
.cch
= wcslen(szBuffer
);
232 InsertMenuItemW(hMenu
, -1, TRUE
, &mii
);
237 LoadOWItems(POPEN_WITH_CONTEXT pContext
, LPCWSTR szName
)
243 szExt
= wcsrchr(szName
, '.');
247 * show default list of available programs
252 /* load programs directly associated from HKCU */
253 LoadItemFromHKCU(pContext
, szExt
);
255 /* load programs associated from HKCR\Extension */
256 LoadItemFromHKCR(pContext
, szExt
);
258 /* load programs referenced from HKCR\ProgId */
259 dwPath
= sizeof(szPath
);
261 if (RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, NULL
, RRF_RT_REG_SZ
, NULL
, szPath
, &dwPath
) == ERROR_SUCCESS
)
263 szPath
[(sizeof(szPath
)/sizeof(WCHAR
))-1] = L
'\0';
264 LoadItemFromHKCR(pContext
, szPath
);
270 static HRESULT WINAPI
SHEOWCm_fnQueryContextMenu(
271 IContextMenu2
*iface
,
279 WCHAR szBuffer
[100] = {0};
281 HMENU hSubMenu
= NULL
;
282 OPEN_WITH_CONTEXT Context
;
283 SHEOWImpl
*This
= impl_from_IContextMenu(iface
);
285 if (LoadStringW(shell32_hInstance
, IDS_OPEN_WITH
, szBuffer
, sizeof(szBuffer
)/sizeof(WCHAR
)) < 0)
287 TRACE("failed to load string\n");
290 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
292 hSubMenu
= CreatePopupMenu();
295 ZeroMemory(&Context
, sizeof(OPEN_WITH_CONTEXT
));
296 Context
.bMenu
= TRUE
;
298 Context
.hMenu
= hSubMenu
;
299 Context
.idCmdFirst
= idCmdFirst
;
301 LoadOWItems(&Context
, This
->szPath
);
304 DestroyMenu(hSubMenu
);
311 AddItem(hSubMenu
, Context
.idCmdFirst
++);
312 This
->count
= Context
.idCmdFirst
- idCmdFirst
;
313 /* verb start at index zero */
314 This
->wId
= This
->count
-1;
315 This
->hSubMenu
= hSubMenu
;
318 pos
= GetMenuDefaultItem(hmenu
, TRUE
, 0) + 1;
320 ZeroMemory(&mii
, sizeof(mii
));
321 mii
.cbSize
= sizeof(mii
);
322 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
325 mii
.fMask
|= MIIM_SUBMENU
;
326 mii
.hSubMenu
= hSubMenu
;
328 mii
.dwTypeData
= (LPWSTR
) szBuffer
;
329 mii
.fState
= MFS_ENABLED
;
332 mii
.fState
|= MFS_DEFAULT
;
335 mii
.wID
= Context
.idCmdFirst
;
336 mii
.fType
= MFT_STRING
;
337 if (InsertMenuItemW( hmenu
, pos
, TRUE
, &mii
))
340 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, Context
.Count
);
344 FreeListItems(HWND hwndDlg
)
347 LRESULT iIndex
, iCount
;
348 POPEN_ITEM_CONTEXT pContext
;
350 hList
= GetDlgItem(hwndDlg
, 14002);
351 iCount
= SendMessageW(hList
, LB_GETCOUNT
, 0, 0);
352 if (iCount
== LB_ERR
)
355 for (iIndex
= 0; iIndex
< iCount
; iIndex
++)
357 pContext
= (POPEN_ITEM_CONTEXT
)SendMessageW(hList
, LB_GETITEMDATA
, iIndex
, 0);
360 DestroyIcon(pContext
->hIcon
);
361 SendMessageW(hList
, LB_SETITEMDATA
, iIndex
, (LPARAM
)0);
362 HeapFree(GetProcessHeap(), 0, pContext
);
367 BOOL
HideApplicationFromList(WCHAR
* pFileName
)
369 WCHAR szBuffer
[100] = {'A','p','p','l','i','c','a','t','i','o','n','s','\\',0};
373 if (wcslen(pFileName
) > (sizeof(szBuffer
)/sizeof(WCHAR
)) - 14)
375 ERR("insufficient buffer\n");
378 wcscpy(&szBuffer
[13], pFileName
);
380 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szBuffer
, L
"NoOpenWith", RRF_RT_REG_SZ
, NULL
, NULL
, &dwSize
);
382 TRACE("result %d szBuffer %s\n", result
, debugstr_w(szBuffer
));
384 if (result
== ERROR_SUCCESS
)
391 WriteStaticShellExtensionKey(HKEY hRootKey
, WCHAR
* pVerb
, WCHAR
*pFullPath
)
395 WCHAR szBuffer
[MAX_PATH
+10] = {'s','h','e','l','l','\\', 0 };
397 if (wcslen(pVerb
) > (sizeof(szBuffer
)/sizeof(WCHAR
)) - 15 ||
398 wcslen(pFullPath
) > (sizeof(szBuffer
)/sizeof(WCHAR
)) - 4)
400 ERR("insufficient buffer\n");
404 /* construct verb reg path */
405 wcscpy(&szBuffer
[6], pVerb
);
406 wcscat(szBuffer
, L
"\\command");
408 /* create verb reg key */
409 if (RegCreateKeyExW(hRootKey
, szBuffer
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hShell
, NULL
) != ERROR_SUCCESS
)
412 /* build command buffer */
413 wcscpy(szBuffer
, pFullPath
);
414 wcscat(szBuffer
, L
" %1");
416 result
= RegSetValueExW(hShell
, NULL
, 0, REG_SZ
, (const BYTE
*)szBuffer
, (wcslen(szBuffer
)+1)* sizeof(WCHAR
));
421 StoreNewSettings(LPCWSTR szFileName
, WCHAR
*szAppName
)
423 WCHAR szBuffer
[100] = { L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\"};
429 /* get file extension */
430 pFileExt
= wcsrchr(szFileName
, L
'.');
431 if (wcslen(pFileExt
) > (sizeof(szBuffer
)/sizeof(WCHAR
)) - 60)
433 ERR("insufficient buffer\n");
436 wcscpy(&szBuffer
[60], pFileExt
);
437 /* open base key for this file extension */
438 if (RegCreateKeyExW(HKEY_CURRENT_USER
, szBuffer
, 0, NULL
, 0, KEY_WRITE
| KEY_READ
, NULL
, &hKey
, NULL
) != ERROR_SUCCESS
)
442 hList
= OpenMRUList(hKey
);
450 /* insert the entry */
451 result
= (*AddMRUStringW
)(hList
, szAppName
);
454 (*FreeMRUListProc
)((HANDLE
)hList
);
455 /* create mru list key */
460 SetProgrammAsDefaultHandler(LPCWSTR szFileName
, WCHAR
* szAppName
)
471 /* extract file extension */
472 pFileExt
= wcsrchr(szFileName
, L
'.');
476 /* create file extension key */
477 if (RegCreateKeyExW(HKEY_CLASSES_ROOT
, pFileExt
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hKey
, &dwDisposition
) != ERROR_SUCCESS
)
480 if (dwDisposition
& REG_CREATED_NEW_KEY
)
482 /* a new entry was created create the prog key id */
483 wcscpy(szBuffer
, &pFileExt
[1]);
484 wcscat(szBuffer
, L
"_auto_file");
485 if (RegSetValueExW(hKey
, NULL
, 0, REG_SZ
, (const BYTE
*)szBuffer
, (wcslen(szBuffer
)+1) * sizeof(WCHAR
)) != ERROR_SUCCESS
)
493 /* entry already exists fetch prog key id */
494 dwSize
= sizeof(szBuffer
);
495 if (RegGetValueW(hKey
, NULL
, NULL
, RRF_RT_REG_SZ
, NULL
, szBuffer
, &dwSize
) != ERROR_SUCCESS
)
501 /* close file extension key */
504 /* create prog id key */
505 if (RegCreateKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hKey
, &dwDisposition
) != ERROR_SUCCESS
)
509 /* check if there already verbs existing for that app */
510 pFileName
= wcsrchr(szAppName
, L
'\\');
511 wcscpy(szBuffer
, L
"Classes\\Applications\\");
512 wcscat(szBuffer
, pFileName
);
513 wcscat(szBuffer
, L
"\\shell");
514 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
, &hAppKey
) == ERROR_SUCCESS
)
516 /* copy static verbs from Classes\Applications key */
518 if (RegCreateKeyExW(hKey
, L
"shell", 0, NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
, &hTemp
, &dwDisposition
) == ERROR_SUCCESS
)
520 result
= RegCopyTreeW(hAppKey
, NULL
, hTemp
);
522 if (result
== ERROR_SUCCESS
)
524 /* copied all subkeys, we are done */
526 RegCloseKey(hAppKey
);
530 RegCloseKey(hAppKey
);
532 /* write standard static shell extension */
533 WriteStaticShellExtensionKey(hKey
, L
"open", szAppName
);
538 BrowseForApplication(HWND hwndDlg
)
540 WCHAR szBuffer
[30] = {0};
541 WCHAR szFilter
[30] = {0};
542 WCHAR szPath
[MAX_PATH
];
544 OPEN_WITH_CONTEXT Context
;
547 /* load resource open with */
548 if (LoadStringW(shell32_hInstance
, IDS_OPEN_WITH
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
)))
550 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
551 ofn
.lpstrTitle
= szBuffer
;
552 ofn
.nMaxFileTitle
= wcslen(szBuffer
);
555 ZeroMemory(&ofn
, sizeof(OPENFILENAMEW
));
556 ofn
.lStructSize
= sizeof(OPENFILENAMEW
);
557 ofn
.hInstance
= shell32_hInstance
;
558 ofn
.Flags
= OFN_PATHMUSTEXIST
| OFN_FILEMUSTEXIST
;
559 ofn
.nMaxFile
= (sizeof(szPath
) / sizeof(WCHAR
));
560 ofn
.lpstrFile
= szPath
;
562 /* load the filter resource string */
563 if (LoadStringW(shell32_hInstance
, IDS_OPEN_WITH_FILTER
, szFilter
, sizeof(szFilter
) / sizeof(WCHAR
)))
565 szFilter
[(sizeof(szFilter
)/sizeof(WCHAR
))-1] = 0;
566 ofn
.lpstrFilter
= szFilter
;
568 ZeroMemory(szPath
, sizeof(szPath
));
570 /* call openfilename */
571 if (!GetOpenFileNameW(&ofn
))
574 /* setup context for insert proc */
575 ZeroMemory(&Context
, sizeof(OPEN_WITH_CONTEXT
));
576 Context
.hDlgCtrl
= GetDlgItem(hwndDlg
, 14002);
577 count
= SendMessage(Context
.hDlgCtrl
, LB_GETCOUNT
, 0, 0);
578 InsertOpenWithItem(&Context
, szPath
);
579 /* select new item */
580 SendMessage(Context
.hDlgCtrl
, LB_SETCURSEL
, count
, 0);
584 GetCurrentOpenItemContext(HWND hwndDlg
)
588 /* get current item */
589 result
= SendDlgItemMessage(hwndDlg
, 14002, LB_GETCURSEL
, 0, 0);
593 /* get item context */
594 result
= SendDlgItemMessage(hwndDlg
, 14002, LB_GETITEMDATA
, result
, 0);
595 if (result
== LB_ERR
)
598 return (POPEN_ITEM_CONTEXT
)result
;
602 ExecuteOpenItem(POPEN_ITEM_CONTEXT pItemContext
, LPCWSTR FileName
)
605 PROCESS_INFORMATION pi
;
606 WCHAR szPath
[(MAX_PATH
* 2)];
608 /* setup path with argument */
609 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
610 si
.cb
= sizeof(STARTUPINFOW
);
611 wcscpy(szPath
, pItemContext
->szAppName
);
612 wcscat(szPath
, L
" ");
613 wcscat(szPath
, FileName
);
615 ERR("path %s\n", debugstr_w(szPath
));
617 if (CreateProcessW(NULL
, szPath
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
))
619 CloseHandle(pi
.hThread
);
620 CloseHandle(pi
.hProcess
);
621 SHAddToRecentDocs(SHARD_PATHW
, FileName
);
626 static INT_PTR CALLBACK
OpenWithProgrammDlg(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
628 LPMEASUREITEMSTRUCT lpmis
;
629 LPDRAWITEMSTRUCT lpdis
;
631 WCHAR szBuffer
[MAX_PATH
+ 30] = { 0 };
634 COLORREF preColor
, preBkColor
;
635 POPEN_ITEM_CONTEXT pItemContext
;
637 OPEN_WITH_CONTEXT Context
;
639 poainfo
= (OPENASINFO
*) GetWindowLongPtr(hwndDlg
, DWLP_USER
);
644 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG
)lParam
);
645 poainfo
= (OPENASINFO
*)lParam
;
646 if (!(poainfo
->oaifInFlags
& OAIF_ALLOW_REGISTRATION
))
647 EnableWindow(GetDlgItem(hwndDlg
, 14003), FALSE
);
648 if (poainfo
->oaifInFlags
& OAIF_FORCE_REGISTRATION
)
649 SendDlgItemMessage(hwndDlg
, 14003, BM_SETCHECK
, BST_CHECKED
, 0);
650 if (poainfo
->oaifInFlags
& OAIF_HIDE_REGISTRATION
)
651 ShowWindow(GetDlgItem(hwndDlg
, 14003), SW_HIDE
);
652 if (poainfo
->pcszFile
)
655 SendDlgItemMessageW(hwndDlg
, 14001, WM_GETTEXT
, sizeof(szBuffer
), (LPARAM
)szBuffer
);
656 index
= wcslen(szBuffer
);
657 if (index
+ wcslen(poainfo
->pcszFile
) + 1 < sizeof(szBuffer
)/sizeof(szBuffer
[0]))
658 wcscat(szBuffer
, poainfo
->pcszFile
);
659 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
660 SendDlgItemMessageW(hwndDlg
, 14001, WM_SETTEXT
, 0, (LPARAM
)szBuffer
);
661 ZeroMemory(&Context
, sizeof(OPEN_WITH_CONTEXT
));
662 Context
.hDlgCtrl
= GetDlgItem(hwndDlg
, 14002);
663 LoadOWItems(&Context
, poainfo
->pcszFile
);
664 SendMessage(Context
.hDlgCtrl
, LB_SETCURSEL
, 0, 0);
668 lpmis
= (LPMEASUREITEMSTRUCT
) lParam
;
669 lpmis
->itemHeight
= 64;
672 switch(LOWORD(wParam
))
674 case 14004: /* browse */
675 BrowseForApplication(hwndDlg
);
678 if (HIWORD(wParam
) == LBN_SELCHANGE
)
679 InvalidateRect((HWND
)lParam
, NULL
, TRUE
); // FIXME USE UPDATE RECT
682 pItemContext
= GetCurrentOpenItemContext(hwndDlg
);
685 /* store settings in HKCU path */
686 StoreNewSettings(poainfo
->pcszFile
, pItemContext
->szAppName
);
688 if (SendDlgItemMessage(hwndDlg
, 14003, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
690 /* set programm as default handler */
691 SetProgrammAsDefaultHandler(poainfo
->pcszFile
, pItemContext
->szAppName
);
694 if (poainfo
->oaifInFlags
& OAIF_EXEC
)
695 ExecuteOpenItem(pItemContext
, poainfo
->pcszFile
);
697 FreeListItems(hwndDlg
);
698 EndDialog(hwndDlg
, 1);
700 case 14006: /* cancel */
701 FreeListItems(hwndDlg
);
702 EndDialog(hwndDlg
, 0);
709 lpdis
= (LPDRAWITEMSTRUCT
) lParam
;
710 if (lpdis
->itemID
== -1)
713 switch (lpdis
->itemAction
)
717 index
= SendMessageW(lpdis
->hwndItem
, LB_GETCURSEL
, 0, 0);
718 pItemContext
=(POPEN_ITEM_CONTEXT
)SendMessage(lpdis
->hwndItem
, LB_GETITEMDATA
, lpdis
->itemID
, (LPARAM
) 0);
720 if (lpdis
->itemID
== index
)
722 /* paint focused item with blue background */
724 hBrush
= CreateSolidBrush(RGB(0, 0, 255));
725 FillRect(lpdis
->hDC
, &lpdis
->rcItem
, hBrush
);
726 DeleteObject(hBrush
);
727 preBkColor
= SetBkColor(lpdis
->hDC
, RGB(255, 255, 255));
731 /* paint non focused item with white background */
733 hBrush
= CreateSolidBrush(RGB(255, 255, 255));
734 FillRect(lpdis
->hDC
, &lpdis
->rcItem
, hBrush
);
735 DeleteObject(hBrush
);
736 preBkColor
= SetBkColor(lpdis
->hDC
, RGB(255, 255, 255));
739 SendMessageW(lpdis
->hwndItem
, LB_GETTEXT
, lpdis
->itemID
, (LPARAM
) szBuffer
);
741 DrawIconEx(lpdis
->hDC
, lpdis
->rcItem
.left
,lpdis
->rcItem
.top
, pItemContext
->hIcon
, 0, 0, 0, NULL
, DI_NORMAL
);
743 GetTextMetrics(lpdis
->hDC
, &mt
);
745 YOffset
= lpdis
->rcItem
.top
+ mt
.tmHeight
/2;
746 TextOutW(lpdis
->hDC
, 45, YOffset
, szBuffer
, wcslen(szBuffer
));
747 /* paint manufacturer description */
748 YOffset
+= mt
.tmHeight
+ 2;
749 preColor
= SetTextColor(lpdis
->hDC
, RGB(192, 192, 192));
750 if (pItemContext
->szManufacturer
[0])
751 TextOutW(lpdis
->hDC
, 45, YOffset
, pItemContext
->szManufacturer
, wcslen(pItemContext
->szManufacturer
));
753 TextOutW(lpdis
->hDC
, 45, YOffset
, pItemContext
->szAppName
, wcslen(pItemContext
->szAppName
));
754 SetTextColor(lpdis
->hDC
, preColor
);
755 SetBkColor(lpdis
->hDC
, preBkColor
);
766 FreeMenuItemContext(HMENU hMenu
)
773 Count
= GetMenuItemCount(hMenu
);
777 /* setup menuitem info */
778 ZeroMemory(&mii
, sizeof(mii
));
779 mii
.cbSize
= sizeof(mii
);
780 mii
.fMask
= MIIM_DATA
| MIIM_FTYPE
;
782 for(Index
= 0; Index
< Count
; Index
++)
784 if (GetMenuItemInfoW(hMenu
, Index
, TRUE
, &mii
))
786 if ((mii
.fType
& MFT_SEPARATOR
) || mii
.dwItemData
== 0)
788 HeapFree(GetProcessHeap(), 0, (LPVOID
)mii
.dwItemData
);
794 static HRESULT WINAPI
795 SHEOWCm_fnInvokeCommand( IContextMenu2
* iface
, LPCMINVOKECOMMANDINFO lpici
)
798 SHEOWImpl
*This
= impl_from_IContextMenu(iface
);
800 ERR("This %p wId %x count %u verb %x\n", This
, This
->wId
, This
->count
, LOWORD(lpici
->lpVerb
));
802 if (This
->wId
< LOWORD(lpici
->lpVerb
))
805 if (This
->wId
== LOWORD(lpici
->lpVerb
))
809 info
.pcszFile
= This
->szPath
;
810 info
.oaifInFlags
= OAIF_ALLOW_REGISTRATION
| OAIF_REGISTER_EXT
| OAIF_EXEC
;
811 info
.pcszClass
= NULL
;
812 FreeMenuItemContext(This
->hSubMenu
);
813 return SHOpenWithDialog(lpici
->hwnd
, &info
);
816 /* retrieve menu item info */
817 ZeroMemory(&mii
, sizeof(mii
));
818 mii
.cbSize
= sizeof(mii
);
819 mii
.fMask
= MIIM_DATA
| MIIM_FTYPE
;
821 if (GetMenuItemInfoW(This
->hSubMenu
, LOWORD(lpici
->lpVerb
), TRUE
, &mii
))
823 POPEN_ITEM_CONTEXT pItemContext
= (POPEN_ITEM_CONTEXT
)mii
.dwItemData
;
826 /* launch item with specified app */
827 ExecuteOpenItem(pItemContext
, This
->szPath
);
830 /* free menu item context */
831 FreeMenuItemContext(This
->hSubMenu
);
835 static HRESULT WINAPI
836 SHEOWCm_fnGetCommandString( IContextMenu2
* iface
, UINT_PTR idCmd
, UINT uType
,
837 UINT
* pwReserved
, LPSTR pszName
, UINT cchMax
)
839 SHEOWImpl
*This
= impl_from_IContextMenu(iface
);
841 FIXME("%p %lu %u %p %p %u\n", This
,
842 idCmd
, uType
, pwReserved
, pszName
, cchMax
);
847 static HRESULT WINAPI
SHEOWCm_fnHandleMenuMsg(
848 IContextMenu2
*iface
,
853 SHEOWImpl
*This
= impl_from_IContextMenu(iface
);
855 TRACE("This %p uMsg %x\n",This
, uMsg
);
860 static const IContextMenu2Vtbl cmvt
=
862 SHEOWCm_fnQueryInterface
,
865 SHEOWCm_fnQueryContextMenu
,
866 SHEOWCm_fnInvokeCommand
,
867 SHEOWCm_fnGetCommandString
,
868 SHEOWCm_fnHandleMenuMsg
872 GetManufacturer(WCHAR
* szAppName
, POPEN_ITEM_CONTEXT pContext
)
879 LPLANGANDCODEPAGE lplangcode
;
884 static const WCHAR wFormat
[] = L
"\\StringFileInfo\\%04x%04x\\CompanyName";
885 static const WCHAR wTranslation
[] = L
"VarFileInfo\\Translation";
887 /* query version info size */
888 VerSize
= GetFileVersionInfoSizeW(szAppName
, &DummyHandle
);
891 pContext
->szManufacturer
[0] = 0;
895 /* allocate buffer */
896 pBuf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, VerSize
);
899 pContext
->szManufacturer
[0] = 0;
903 /* query version info */
904 if(!GetFileVersionInfoW(szAppName
, 0, VerSize
, pBuf
))
906 pContext
->szManufacturer
[0] = 0;
907 HeapFree(GetProcessHeap(), 0, pBuf
);
911 /* query lang code */
912 if(VerQueryValueW(pBuf
, wTranslation
, (LPVOID
*)&lplangcode
, &VerSize
))
914 /* FIXME find language from current locale / if not available,
916 * for now default to first available language
918 lang
= lplangcode
->lang
;
919 code
= lplangcode
->code
;
922 swprintf(szBuffer
, wFormat
, lang
, code
);
923 /* query manufacturer */
925 bResult
= VerQueryValueW(pBuf
, szBuffer
, (LPVOID
*)&pResult
, &VerSize
);
927 if (VerSize
&& bResult
&& pResult
)
928 wcscpy(pContext
->szManufacturer
, pResult
);
930 pContext
->szManufacturer
[0] = 0;
931 HeapFree(GetProcessHeap(), 0, pBuf
);
938 InsertOpenWithItem(POPEN_WITH_CONTEXT pContext
, WCHAR
* szAppName
)
941 POPEN_ITEM_CONTEXT pItemContext
;
944 WCHAR Buffer
[_MAX_FNAME
];
946 pItemContext
= HeapAlloc(GetProcessHeap(), 0, sizeof(OPEN_ITEM_CONTEXT
));
951 wcscpy(pItemContext
->szAppName
, szAppName
);
952 /* null terminate it */
953 pItemContext
->szAppName
[MAX_PATH
-1] = 0;
954 /* extract path name */
955 _wsplitpath(szAppName
, NULL
, NULL
, Buffer
, NULL
);
956 Offset
= wcsrchr(Buffer
, '.');
959 Buffer
[0] = towupper(Buffer
[0]);
963 ZeroMemory(&mii
, sizeof(mii
));
964 mii
.cbSize
= sizeof(mii
);
965 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
| MIIM_DATA
;
966 mii
.fType
= MFT_STRING
; //MFT_OWNERDRAW;
967 mii
.fState
= MFS_ENABLED
;
968 mii
.wID
= pContext
->idCmdFirst
;
969 mii
.dwTypeData
= Buffer
;
970 mii
.cch
= wcslen(Buffer
);
971 mii
.dwItemData
= (ULONG_PTR
)pItemContext
;
972 wcscpy(pItemContext
->szManufacturer
, Buffer
);
973 if (InsertMenuItemW(pContext
->hMenu
, -1, TRUE
, &mii
))
975 pContext
->idCmdFirst
++;
981 /* get default icon */
982 pItemContext
->hIcon
= ExtractIconW(shell32_hInstance
, szAppName
, 0);
983 /* get manufacturer */
984 GetManufacturer(pItemContext
->szAppName
, pItemContext
);
985 index
= SendMessageW(pContext
->hDlgCtrl
, LB_ADDSTRING
, 0, (LPARAM
)Buffer
);
987 SendMessageW(pContext
->hDlgCtrl
, LB_SETITEMDATA
, index
, (LPARAM
)pItemContext
);
992 AddItemFromProgIDList(POPEN_WITH_CONTEXT pContext
, HKEY hKey
)
994 FIXME("implement me :)))\n");
998 OpenMRUList(HKEY hKey
)
1004 WCHAR szPath
[MAX_PATH
];
1005 if (!GetSystemDirectoryW(szPath
, MAX_PATH
))
1007 PathAddBackslashW(szPath
);
1008 wcscat(szPath
, L
"comctl32.dll");
1009 hModule
= LoadLibraryExW(szPath
, NULL
, 0);
1011 CreateMRUListProcW
= (CREATEMRULISTPROCW
)GetProcAddress(hModule
, MAKEINTRESOURCEA(400));
1012 EnumMRUListW
= (ENUMMRULISTW
)GetProcAddress(hModule
, MAKEINTRESOURCEA(403));
1013 FreeMRUListProc
= (FREEMRULIST
)GetProcAddress(hModule
, MAKEINTRESOURCEA(152));
1014 AddMRUStringW
= (ADDMRUSTRINGW
)GetProcAddress(hModule
, MAKEINTRESOURCEA(401));
1016 if (!CreateMRUListProcW
|| !EnumMRUListW
|| !FreeMRUListProc
|| !AddMRUStringW
)
1019 /* initialize mru list info */
1020 info
.cbSize
= sizeof(MRUINFO
);
1022 info
.fFlags
= MRUF_STRING_LIST
;
1024 info
.lpszSubKey
= L
"OpenWithList";
1025 info
.lpfnCompare
= NULL
;
1028 return (*CreateMRUListProcW
)(&info
);
1032 AddItemFromMRUList(POPEN_WITH_CONTEXT pContext
, HKEY hKey
)
1035 int nItem
, nCount
, nResult
;
1036 WCHAR szBuffer
[MAX_PATH
];
1039 hList
= OpenMRUList(hKey
);
1043 /* get list count */
1044 nCount
= (*EnumMRUListW
)((HANDLE
)hList
, -1, NULL
, 0);
1046 for(nItem
= 0; nItem
< nCount
; nItem
++)
1048 nResult
= (*EnumMRUListW
)((HANDLE
)hList
, nItem
, szBuffer
, MAX_PATH
);
1051 /* make sure its zero terminated */
1052 szBuffer
[min(MAX_PATH
-1, nResult
)] = '\0';
1054 if (!HideApplicationFromList(szBuffer
))
1055 InsertOpenWithItem(pContext
, szBuffer
);
1058 /* free the mru list */
1059 (*FreeMRUList
)((HANDLE
)hList
);
1065 LoadItemFromHKCR(POPEN_WITH_CONTEXT pContext
, WCHAR
* szExt
)
1069 WCHAR szBuffer
[MAX_PATH
+10];
1070 WCHAR szResult
[100];
1073 static const WCHAR szOpenWithList
[] = L
"OpenWithList";
1074 static const WCHAR szOpenWithProgIds
[] = L
"OpenWithProgIDs";
1075 static const WCHAR szPerceivedType
[] = L
"PerceivedType";
1076 static const WCHAR szSysFileAssoc
[] = L
"SystemFileAssociations\\%s";
1078 /* check if extension exists */
1079 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szExt
, 0, KEY_READ
| KEY_WRITE
, &hKey
) != ERROR_SUCCESS
)
1082 if (RegGetValueW(hKey
, NULL
, L
"NoOpen", RRF_RT_REG_SZ
, NULL
, NULL
, &dwSize
) == ERROR_SUCCESS
)
1084 /* display warning dialog */
1085 pContext
->NoOpen
= TRUE
;
1088 /* check if there is a directly available execute key */
1089 if (RegOpenKeyExW(hKey
, L
"shell\\open\\command", 0, KEY_READ
, &hSubKey
) == ERROR_SUCCESS
)
1091 DWORD dwBuffer
= sizeof(szBuffer
);
1093 if (RegGetValueW(hSubKey
, NULL
, NULL
, RRF_RT_REG_SZ
, NULL
, (PVOID
)szBuffer
, &dwBuffer
) == ERROR_SUCCESS
)
1095 WCHAR
* Ext
= wcsrchr(szBuffer
, ' ');
1098 /* erase %1 or extra arguments */
1101 if(!HideApplicationFromList(szBuffer
))
1102 InsertOpenWithItem(pContext
, szBuffer
);
1104 RegCloseKey(hSubKey
);
1107 /* load items from HKCR\Ext\OpenWithList */
1108 if (RegOpenKeyExW(hKey
, szOpenWithList
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hSubKey
) == ERROR_SUCCESS
)
1110 AddItemFromMRUList(pContext
, hKey
);
1111 RegCloseKey(hSubKey
);
1114 /* load items from HKCR\Ext\OpenWithProgIDs */
1115 if (RegOpenKeyExW(hKey
, szOpenWithProgIds
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hSubKey
) == ERROR_SUCCESS
)
1117 AddItemFromProgIDList(pContext
, hSubKey
);
1118 RegCloseKey(hSubKey
);
1121 /* load items from SystemFileAssociations\Ext key */
1122 swprintf(szResult
, szSysFileAssoc
, szExt
);
1123 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szResult
, 0, KEY_READ
| KEY_WRITE
, &hSubKey
) == ERROR_SUCCESS
)
1125 AddItemFromMRUList(pContext
, hSubKey
);
1126 RegCloseKey(hSubKey
);
1129 /* load additional items from referenced PerceivedType*/
1130 dwSize
= sizeof(szBuffer
);
1131 if (RegGetValueW(hKey
, NULL
, szPerceivedType
, RRF_RT_REG_SZ
, NULL
, szBuffer
, &dwSize
) != ERROR_SUCCESS
)
1138 /* terminate it explictely */
1140 swprintf(szResult
, szSysFileAssoc
, szBuffer
);
1141 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szResult
, 0, KEY_READ
| KEY_WRITE
, &hSubKey
) == ERROR_SUCCESS
)
1143 AddItemFromMRUList(pContext
, hSubKey
);
1144 RegCloseKey(hSubKey
);
1149 LoadItemFromHKCU(POPEN_WITH_CONTEXT pContext
, WCHAR
* szExt
)
1151 WCHAR szBuffer
[MAX_PATH
];
1154 static const WCHAR szOpenWithProgIDs
[] = L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s\\OpenWithProgIDs";
1155 static const WCHAR szOpenWithList
[] = L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s";
1157 /* handle first progid lists */
1158 swprintf(szBuffer
, szOpenWithProgIDs
, szExt
);
1159 if (RegOpenKeyExW(HKEY_CURRENT_USER
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
) == ERROR_SUCCESS
)
1161 AddItemFromProgIDList(pContext
, hKey
);
1165 /* now handle mru lists */
1166 swprintf(szBuffer
, szOpenWithList
, szExt
);
1167 if (RegOpenKeyExW(HKEY_CURRENT_USER
, szBuffer
, 0, KEY_READ
| KEY_WRITE
, &hKey
) == ERROR_SUCCESS
)
1169 AddItemFromMRUList(pContext
, hKey
);
1175 SHEOW_LoadOpenWithItems(SHEOWImpl
*This
, IDataObject
*pdtobj
)
1181 LPCITEMIDLIST pidl_folder
;
1182 LPCITEMIDLIST pidl_child
;
1186 static const WCHAR szShortCut
[] = { '.','l','n','k', 0 };
1188 fmt
.cfFormat
= RegisterClipboardFormatW(CFSTR_SHELLIDLIST
);
1190 fmt
.dwAspect
= DVASPECT_CONTENT
;
1192 fmt
.tymed
= TYMED_HGLOBAL
;
1194 hr
= IDataObject_GetData(pdtobj
, &fmt
, &medium
);
1198 ERR("IDataObject_GetData failed with 0x%x\n", hr
);
1202 /*assert(pida->cidl==1);*/
1203 pida
= (LPIDA
)GlobalLock(medium
.u
.hGlobal
);
1205 pidl_folder
= (LPCITEMIDLIST
) ((LPBYTE
)pida
+pida
->aoffset
[0]);
1206 pidl_child
= (LPCITEMIDLIST
) ((LPBYTE
)pida
+pida
->aoffset
[1]);
1208 pidl
= ILCombine(pidl_folder
, pidl_child
);
1210 GlobalUnlock(medium
.u
.hGlobal
);
1211 GlobalFree(medium
.u
.hGlobal
);
1216 return E_OUTOFMEMORY
;
1218 if (_ILIsDesktop(pidl_child
) || _ILIsMyDocuments(pidl_child
) || _ILIsControlPanel(pidl_child
) || _ILIsNetHood(pidl_child
) ||
1219 _ILIsBitBucket(pidl_child
) || _ILIsDrive(pidl_child
) || _ILIsCPanelStruct(pidl_child
) || _ILIsFolder(pidl_child
) || _ILIsControlPanel(pidl_folder
))
1221 TRACE("pidl is a folder\n");
1222 SHFree((void*)pidl
);
1226 if (!SHGetPathFromIDListW(pidl
, This
->szPath
))
1228 SHFree((void*)pidl
);
1229 ERR("SHGetPathFromIDListW failed\n");
1233 SHFree((void*)pidl
);
1234 TRACE("szPath %s\n", debugstr_w(This
->szPath
));
1236 if (GetBinaryTypeW(This
->szPath
, &dwPath
))
1238 TRACE("path is a executable %x\n", dwPath
);
1242 szPtr
= wcsrchr(This
->szPath
, '.');
1245 if (!_wcsicmp(szPtr
, szShortCut
))
1247 FIXME("pidl is a shortcut\n");
1254 static HRESULT WINAPI
1255 SHEOW_ExtInit_Initialize( IShellExtInit
* iface
, LPCITEMIDLIST pidlFolder
,
1256 IDataObject
*pdtobj
, HKEY hkeyProgID
)
1258 SHEOWImpl
*This
= impl_from_IShellExtInit(iface
);
1260 TRACE("This %p\n", This
);
1262 return SHEOW_LoadOpenWithItems(This
, pdtobj
);
1265 static ULONG WINAPI
SHEOW_ExtInit_AddRef(IShellExtInit
*iface
)
1267 SHEOWImpl
*This
= impl_from_IShellExtInit(iface
);
1268 ULONG refCount
= InterlockedIncrement(&This
->ref
);
1270 TRACE("(%p)->(count=%u)\n", This
, refCount
- 1);
1275 static ULONG WINAPI
SHEOW_ExtInit_Release(IShellExtInit
*iface
)
1277 SHEOWImpl
*This
= impl_from_IShellExtInit(iface
);
1278 ULONG refCount
= InterlockedDecrement(&This
->ref
);
1280 TRACE("(%p)->(count=%i)\n", This
, refCount
+ 1);
1284 HeapFree(GetProcessHeap(),0,This
);
1289 static HRESULT WINAPI
1290 SHEOW_ExtInit_QueryInterface( IShellExtInit
* iface
, REFIID riid
, void** ppvObject
)
1292 SHEOWImpl
*This
= impl_from_IShellExtInit(iface
);
1293 return SHEOWCm_fnQueryInterface((IContextMenu2
*)This
, riid
, ppvObject
);
1296 static const IShellExtInitVtbl eivt
=
1298 SHEOW_ExtInit_QueryInterface
,
1299 SHEOW_ExtInit_AddRef
,
1300 SHEOW_ExtInit_Release
,
1301 SHEOW_ExtInit_Initialize
1305 HRESULT WINAPI
SHOpenWithDialog(
1307 const OPENASINFO
*poainfo
1314 if (poainfo
->pcszClass
== NULL
&& poainfo
->pcszFile
== NULL
)
1318 hwnd
= CreateDialogParam(shell32_hInstance
, MAKEINTRESOURCE(OPEN_WITH_PROGRAMM_DLG
), hwndParent
, OpenWithProgrammDlg
, (LPARAM
)poainfo
);
1321 ERR("Failed to create dialog\n");
1324 ShowWindow(hwnd
, SW_SHOWNORMAL
);
1326 while ((bRet
= GetMessage(&msg
, NULL
, 0, 0)) != 0)
1328 if (!IsWindow(hwnd
) || !IsDialogMessage(hwnd
, &msg
))
1330 TranslateMessage(&msg
);
1331 DispatchMessage(&msg
);