2 * Open With Context Menu extension
4 * Copyright 2007 Johannes Anderwald <janderwald@reactos.org>
5 * Copyright 2009 Andrew Hill
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 WINE_DEFAULT_DEBUG_CHANNEL (shell
);
27 /// [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system]
28 /// "NoInternetOpenWith"=dword:00000001
32 // implement duplicate checks in list box
33 // implement duplicate checks for MRU!
34 // implement owner drawn menu
44 }OPEN_WITH_CONTEXT
, *POPEN_WITH_CONTEXT
;
46 #define MANUFACTURER_NAME_SIZE 100
51 WCHAR szAppName
[MAX_PATH
];
52 WCHAR szManufacturer
[MANUFACTURER_NAME_SIZE
];
53 }OPEN_ITEM_CONTEXT
, *POPEN_ITEM_CONTEXT
;
56 typedef struct _LANGANDCODEPAGE_
60 } LANGANDCODEPAGE
, *LPLANGANDCODEPAGE
;
62 HANDLE
OpenMRUList(HKEY hKey
);
64 void LoadItemFromHKCU(POPEN_WITH_CONTEXT pContext
, const WCHAR
* szExt
);
65 void LoadItemFromHKCR(POPEN_WITH_CONTEXT pContext
, const WCHAR
* szExt
);
66 void InsertOpenWithItem(POPEN_WITH_CONTEXT pContext
, WCHAR
* szAppName
);
68 COpenWithMenu::COpenWithMenu()
74 COpenWithMenu::~COpenWithMenu()
76 TRACE(" destroying IContextMenu(%p)\n", this);
80 AddItem(HMENU hMenu
, UINT idCmdFirst
)
83 WCHAR szBuffer
[MAX_PATH
];
84 static const WCHAR szChoose
[] = { 'C','h','o','o','s','e',' ','P','r','o','g','r','a','m','.','.','.',0 };
86 ZeroMemory(&mii
, sizeof(mii
));
87 mii
.cbSize
= sizeof(mii
);
88 mii
.fMask
= MIIM_TYPE
| MIIM_ID
;
89 mii
.fType
= MFT_SEPARATOR
;
91 InsertMenuItemW(hMenu
, -1, TRUE
, &mii
);
93 if (!LoadStringW(shell32_hInstance
, IDS_OPEN_WITH_CHOOSE
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
)))
94 wcscpy(szBuffer
, szChoose
);
96 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
98 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
99 mii
.fType
= MFT_STRING
;
100 mii
.fState
= MFS_ENABLED
;
101 mii
.wID
= idCmdFirst
;
102 mii
.dwTypeData
= (LPWSTR
)szBuffer
;
103 mii
.cch
= wcslen(szBuffer
);
105 InsertMenuItemW(hMenu
, -1, TRUE
, &mii
);
110 LoadOWItems(POPEN_WITH_CONTEXT pContext
, LPCWSTR szName
)
116 szExt
= wcsrchr(szName
, '.');
120 * show default list of available programs
125 /* load programs directly associated from HKCU */
126 LoadItemFromHKCU(pContext
, szExt
);
128 /* load programs associated from HKCR\Extension */
129 LoadItemFromHKCR(pContext
, szExt
);
131 /* load programs referenced from HKCR\ProgId */
132 dwPath
= sizeof(szPath
);
134 if (RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, NULL
, RRF_RT_REG_SZ
, NULL
, szPath
, &dwPath
) == ERROR_SUCCESS
)
136 szPath
[(sizeof(szPath
)/sizeof(WCHAR
))-1] = L
'\0';
137 LoadItemFromHKCR(pContext
, szPath
);
143 HRESULT WINAPI
COpenWithMenu::QueryContextMenu(
151 WCHAR szBuffer
[100] = {0};
153 HMENU hSubMenu
= NULL
;
154 OPEN_WITH_CONTEXT Context
;
156 if (LoadStringW(shell32_hInstance
, IDS_OPEN_WITH
, szBuffer
, sizeof(szBuffer
)/sizeof(WCHAR
)) < 0)
158 TRACE("failed to load string\n");
161 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
163 hSubMenu
= CreatePopupMenu();
166 ZeroMemory(&Context
, sizeof(OPEN_WITH_CONTEXT
));
167 Context
.bMenu
= TRUE
;
169 Context
.hMenu
= hSubMenu
;
170 Context
.idCmdFirst
= idCmdFirst
;
172 LoadOWItems(&Context
, szPath
);
175 DestroyMenu(hSubMenu
);
182 AddItem(hSubMenu
, Context
.idCmdFirst
++);
183 count
= Context
.idCmdFirst
- idCmdFirst
;
184 /* verb start at index zero */
189 pos
= GetMenuDefaultItem(hmenu
, TRUE
, 0) + 1;
191 ZeroMemory(&mii
, sizeof(mii
));
192 mii
.cbSize
= sizeof(mii
);
193 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
196 mii
.fMask
|= MIIM_SUBMENU
;
197 mii
.hSubMenu
= hSubMenu
;
199 mii
.dwTypeData
= (LPWSTR
) szBuffer
;
200 mii
.fState
= MFS_ENABLED
;
203 mii
.fState
|= MFS_DEFAULT
;
206 mii
.wID
= Context
.idCmdFirst
;
207 mii
.fType
= MFT_STRING
;
208 if (InsertMenuItemW( hmenu
, pos
, TRUE
, &mii
))
211 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, Context
.Count
);
215 FreeListItems(HWND hwndDlg
)
218 LRESULT iIndex
, iCount
;
219 POPEN_ITEM_CONTEXT pContext
;
221 hList
= GetDlgItem(hwndDlg
, 14002);
222 iCount
= SendMessageW(hList
, LB_GETCOUNT
, 0, 0);
223 if (iCount
== LB_ERR
)
226 for (iIndex
= 0; iIndex
< iCount
; iIndex
++)
228 pContext
= (POPEN_ITEM_CONTEXT
)SendMessageW(hList
, LB_GETITEMDATA
, iIndex
, 0);
231 DestroyIcon(pContext
->hIcon
);
232 SendMessageW(hList
, LB_SETITEMDATA
, iIndex
, (LPARAM
)0);
233 HeapFree(GetProcessHeap(), 0, pContext
);
238 BOOL
HideApplicationFromList(WCHAR
* pFileName
)
240 WCHAR szBuffer
[100] = {'A','p','p','l','i','c','a','t','i','o','n','s','\\',0};
244 if (wcslen(pFileName
) > (sizeof(szBuffer
)/sizeof(WCHAR
)) - 14)
246 ERR("insufficient buffer\n");
249 wcscpy(&szBuffer
[13], pFileName
);
251 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szBuffer
, L
"NoOpenWith", RRF_RT_REG_SZ
, NULL
, NULL
, &dwSize
);
253 TRACE("result %d szBuffer %s\n", result
, debugstr_w(szBuffer
));
255 if (result
== ERROR_SUCCESS
)
262 WriteStaticShellExtensionKey(HKEY hRootKey
, const WCHAR
* pVerb
, WCHAR
*pFullPath
)
266 WCHAR szBuffer
[MAX_PATH
+10] = {'s','h','e','l','l','\\', 0 };
268 if (wcslen(pVerb
) > (sizeof(szBuffer
)/sizeof(WCHAR
)) - 15 ||
269 wcslen(pFullPath
) > (sizeof(szBuffer
)/sizeof(WCHAR
)) - 4)
271 ERR("insufficient buffer\n");
275 /* construct verb reg path */
276 wcscpy(&szBuffer
[6], pVerb
);
277 wcscat(szBuffer
, L
"\\command");
279 /* create verb reg key */
280 if (RegCreateKeyExW(hRootKey
, szBuffer
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hShell
, NULL
) != ERROR_SUCCESS
)
283 /* build command buffer */
284 wcscpy(szBuffer
, pFullPath
);
285 wcscat(szBuffer
, L
" %1");
287 result
= RegSetValueExW(hShell
, NULL
, 0, REG_SZ
, (const BYTE
*)szBuffer
, (wcslen(szBuffer
)+1)* sizeof(WCHAR
));
292 StoreNewSettings(LPCWSTR szFileName
, WCHAR
*szAppName
)
294 WCHAR szBuffer
[100] = { L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\"};
295 const WCHAR
* pFileExt
;
300 /* get file extension */
301 pFileExt
= wcsrchr(szFileName
, L
'.');
302 if (wcslen(pFileExt
) > (sizeof(szBuffer
)/sizeof(WCHAR
)) - 60)
304 ERR("insufficient buffer\n");
307 wcscpy(&szBuffer
[60], pFileExt
);
308 /* open base key for this file extension */
309 if (RegCreateKeyExW(HKEY_CURRENT_USER
, szBuffer
, 0, NULL
, 0, KEY_WRITE
| KEY_READ
, NULL
, &hKey
, NULL
) != ERROR_SUCCESS
)
313 hList
= OpenMRUList(hKey
);
321 /* insert the entry */
322 result
= AddMRUStringW(hList
, szAppName
);
326 /* create mru list key */
331 SetProgrammAsDefaultHandler(LPCWSTR szFileName
, WCHAR
* szAppName
)
339 const WCHAR
* pFileExt
;
342 /* extract file extension */
343 pFileExt
= wcsrchr(szFileName
, L
'.');
347 /* create file extension key */
348 if (RegCreateKeyExW(HKEY_CLASSES_ROOT
, pFileExt
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hKey
, &dwDisposition
) != ERROR_SUCCESS
)
351 if (dwDisposition
& REG_CREATED_NEW_KEY
)
353 /* a new entry was created create the prog key id */
354 wcscpy(szBuffer
, &pFileExt
[1]);
355 wcscat(szBuffer
, L
"_auto_file");
356 if (RegSetValueExW(hKey
, NULL
, 0, REG_SZ
, (const BYTE
*)szBuffer
, (wcslen(szBuffer
)+1) * sizeof(WCHAR
)) != ERROR_SUCCESS
)
364 /* entry already exists fetch prog key id */
365 dwSize
= sizeof(szBuffer
);
366 if (RegGetValueW(hKey
, NULL
, NULL
, RRF_RT_REG_SZ
, NULL
, szBuffer
, &dwSize
) != ERROR_SUCCESS
)
372 /* close file extension key */
375 /* create prog id key */
376 if (RegCreateKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hKey
, &dwDisposition
) != ERROR_SUCCESS
)
380 /* check if there already verbs existing for that app */
381 pFileName
= wcsrchr(szAppName
, L
'\\');
382 wcscpy(szBuffer
, L
"Classes\\Applications\\");
383 wcscat(szBuffer
, pFileName
);
384 wcscat(szBuffer
, L
"\\shell");
385 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
, &hAppKey
) == ERROR_SUCCESS
)
387 /* copy static verbs from Classes\Applications key */
389 if (RegCreateKeyExW(hKey
, L
"shell", 0, NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
, &hTemp
, &dwDisposition
) == ERROR_SUCCESS
)
391 result
= RegCopyTreeW(hAppKey
, NULL
, hTemp
);
393 if (result
== ERROR_SUCCESS
)
395 /* copied all subkeys, we are done */
397 RegCloseKey(hAppKey
);
401 RegCloseKey(hAppKey
);
403 /* write standard static shell extension */
404 WriteStaticShellExtensionKey(hKey
, L
"open", szAppName
);
409 BrowseForApplication(HWND hwndDlg
)
411 WCHAR szBuffer
[64] = {0};
412 WCHAR szFilter
[256] = {0};
413 WCHAR szPath
[MAX_PATH
];
415 OPEN_WITH_CONTEXT Context
;
418 /* load resource open with */
419 if (LoadStringW(shell32_hInstance
, IDS_OPEN_WITH
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
)))
421 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
422 ofn
.lpstrTitle
= szBuffer
;
423 ofn
.nMaxFileTitle
= wcslen(szBuffer
);
426 ZeroMemory(&ofn
, sizeof(OPENFILENAMEW
));
427 ofn
.lStructSize
= sizeof(OPENFILENAMEW
);
428 ofn
.hInstance
= shell32_hInstance
;
429 ofn
.Flags
= OFN_PATHMUSTEXIST
| OFN_FILEMUSTEXIST
;
430 ofn
.nMaxFile
= (sizeof(szPath
) / sizeof(WCHAR
));
431 ofn
.lpstrFile
= szPath
;
433 /* load the filter resource string */
434 if (LoadStringW(shell32_hInstance
, IDS_OPEN_WITH_FILTER
, szFilter
, sizeof(szFilter
) / sizeof(WCHAR
)))
436 szFilter
[(sizeof(szFilter
)/sizeof(WCHAR
))-1] = 0;
437 ofn
.lpstrFilter
= szFilter
;
439 ZeroMemory(szPath
, sizeof(szPath
));
441 /* call openfilename */
442 if (!GetOpenFileNameW(&ofn
))
445 /* setup context for insert proc */
446 ZeroMemory(&Context
, sizeof(OPEN_WITH_CONTEXT
));
447 Context
.hDlgCtrl
= GetDlgItem(hwndDlg
, 14002);
448 count
= SendMessage(Context
.hDlgCtrl
, LB_GETCOUNT
, 0, 0);
449 InsertOpenWithItem(&Context
, szPath
);
450 /* select new item */
451 SendMessage(Context
.hDlgCtrl
, LB_SETCURSEL
, count
, 0);
455 GetCurrentOpenItemContext(HWND hwndDlg
)
459 /* get current item */
460 result
= SendDlgItemMessage(hwndDlg
, 14002, LB_GETCURSEL
, 0, 0);
464 /* get item context */
465 result
= SendDlgItemMessage(hwndDlg
, 14002, LB_GETITEMDATA
, result
, 0);
466 if (result
== LB_ERR
)
469 return (POPEN_ITEM_CONTEXT
)result
;
473 ExecuteOpenItem(POPEN_ITEM_CONTEXT pItemContext
, LPCWSTR FileName
)
476 PROCESS_INFORMATION pi
;
477 WCHAR szPath
[(MAX_PATH
* 2)];
479 /* setup path with argument */
480 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
481 si
.cb
= sizeof(STARTUPINFOW
);
482 wcscpy(szPath
, pItemContext
->szAppName
);
483 wcscat(szPath
, L
" ");
484 wcscat(szPath
, FileName
);
486 ERR("path %s\n", debugstr_w(szPath
));
488 if (CreateProcessW(NULL
, szPath
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
))
490 CloseHandle(pi
.hThread
);
491 CloseHandle(pi
.hProcess
);
492 SHAddToRecentDocs(SHARD_PATHW
, FileName
);
497 static INT_PTR CALLBACK
OpenWithProgrammDlg(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
499 LPMEASUREITEMSTRUCT lpmis
;
500 LPDRAWITEMSTRUCT lpdis
;
502 WCHAR szBuffer
[MAX_PATH
+ 30] = { 0 };
505 COLORREF preColor
, preBkColor
;
506 POPEN_ITEM_CONTEXT pItemContext
;
508 OPEN_WITH_CONTEXT Context
;
510 poainfo
= (OPENASINFO
*) GetWindowLongPtr(hwndDlg
, DWLP_USER
);
515 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG
)lParam
);
516 poainfo
= (OPENASINFO
*)lParam
;
517 if (!(poainfo
->oaifInFlags
& OAIF_ALLOW_REGISTRATION
))
518 EnableWindow(GetDlgItem(hwndDlg
, 14003), FALSE
);
519 if (poainfo
->oaifInFlags
& OAIF_FORCE_REGISTRATION
)
520 SendDlgItemMessage(hwndDlg
, 14003, BM_SETCHECK
, BST_CHECKED
, 0);
521 if (poainfo
->oaifInFlags
& OAIF_HIDE_REGISTRATION
)
522 ShowWindow(GetDlgItem(hwndDlg
, 14003), SW_HIDE
);
523 if (poainfo
->pcszFile
)
526 SendDlgItemMessageW(hwndDlg
, 14001, WM_GETTEXT
, sizeof(szBuffer
), (LPARAM
)szBuffer
);
527 index
= wcslen(szBuffer
);
528 if (index
+ wcslen(poainfo
->pcszFile
) + 1 < sizeof(szBuffer
)/sizeof(szBuffer
[0]))
529 wcscat(szBuffer
, poainfo
->pcszFile
);
530 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
531 SendDlgItemMessageW(hwndDlg
, 14001, WM_SETTEXT
, 0, (LPARAM
)szBuffer
);
532 ZeroMemory(&Context
, sizeof(OPEN_WITH_CONTEXT
));
533 Context
.hDlgCtrl
= GetDlgItem(hwndDlg
, 14002);
534 LoadOWItems(&Context
, poainfo
->pcszFile
);
535 SendMessage(Context
.hDlgCtrl
, LB_SETCURSEL
, 0, 0);
539 lpmis
= (LPMEASUREITEMSTRUCT
) lParam
;
540 lpmis
->itemHeight
= 64;
543 switch(LOWORD(wParam
))
545 case 14004: /* browse */
546 BrowseForApplication(hwndDlg
);
549 if (HIWORD(wParam
) == LBN_SELCHANGE
)
550 InvalidateRect((HWND
)lParam
, NULL
, TRUE
); // FIXME USE UPDATE RECT
553 pItemContext
= GetCurrentOpenItemContext(hwndDlg
);
556 /* store settings in HKCU path */
557 StoreNewSettings(poainfo
->pcszFile
, pItemContext
->szAppName
);
559 if (SendDlgItemMessage(hwndDlg
, 14003, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
561 /* set programm as default handler */
562 SetProgrammAsDefaultHandler(poainfo
->pcszFile
, pItemContext
->szAppName
);
565 if (poainfo
->oaifInFlags
& OAIF_EXEC
)
566 ExecuteOpenItem(pItemContext
, poainfo
->pcszFile
);
568 FreeListItems(hwndDlg
);
569 EndDialog(hwndDlg
, 1);
571 case 14006: /* cancel */
572 FreeListItems(hwndDlg
);
573 EndDialog(hwndDlg
, 0);
580 lpdis
= (LPDRAWITEMSTRUCT
) lParam
;
581 if ((int)lpdis
->itemID
== -1)
584 switch (lpdis
->itemAction
)
588 index
= SendMessageW(lpdis
->hwndItem
, LB_GETCURSEL
, 0, 0);
589 pItemContext
=(POPEN_ITEM_CONTEXT
)SendMessage(lpdis
->hwndItem
, LB_GETITEMDATA
, lpdis
->itemID
, (LPARAM
) 0);
591 if ((int)lpdis
->itemID
== index
)
593 /* paint focused item with standard background colour */
595 hBrush
= CreateSolidBrush(RGB(46, 104, 160));
596 FillRect(lpdis
->hDC
, &lpdis
->rcItem
, hBrush
);
597 DeleteObject(hBrush
);
598 preBkColor
= SetBkColor(lpdis
->hDC
, RGB(46, 104, 160));
602 /* paint non focused item with white background */
604 hBrush
= CreateSolidBrush(RGB(255, 255, 255));
605 FillRect(lpdis
->hDC
, &lpdis
->rcItem
, hBrush
);
606 DeleteObject(hBrush
);
607 preBkColor
= SetBkColor(lpdis
->hDC
, RGB(255, 255, 255));
610 SendMessageW(lpdis
->hwndItem
, LB_GETTEXT
, lpdis
->itemID
, (LPARAM
) szBuffer
);
612 DrawIconEx(lpdis
->hDC
, lpdis
->rcItem
.left
,lpdis
->rcItem
.top
, pItemContext
->hIcon
, 0, 0, 0, NULL
, DI_NORMAL
);
614 GetTextMetrics(lpdis
->hDC
, &mt
);
616 YOffset
= lpdis
->rcItem
.top
+ mt
.tmHeight
/2;
617 TextOutW(lpdis
->hDC
, 45, YOffset
, szBuffer
, wcslen(szBuffer
));
618 /* paint manufacturer description */
619 YOffset
+= mt
.tmHeight
+ 2;
620 preColor
= SetTextColor(lpdis
->hDC
, RGB(192, 192, 192));
621 if (pItemContext
->szManufacturer
[0])
622 TextOutW(lpdis
->hDC
, 45, YOffset
, pItemContext
->szManufacturer
, wcslen(pItemContext
->szManufacturer
));
624 TextOutW(lpdis
->hDC
, 45, YOffset
, pItemContext
->szAppName
, wcslen(pItemContext
->szAppName
));
625 SetTextColor(lpdis
->hDC
, preColor
);
626 SetBkColor(lpdis
->hDC
, preBkColor
);
631 FreeListItems(hwndDlg
);
632 EndDialog(hwndDlg
, 0);
641 FreeMenuItemContext(HMENU hMenu
)
648 Count
= GetMenuItemCount(hMenu
);
652 /* setup menuitem info */
653 ZeroMemory(&mii
, sizeof(mii
));
654 mii
.cbSize
= sizeof(mii
);
655 mii
.fMask
= MIIM_DATA
| MIIM_FTYPE
;
657 for(Index
= 0; Index
< Count
; Index
++)
659 if (GetMenuItemInfoW(hMenu
, Index
, TRUE
, &mii
))
661 if ((mii
.fType
& MFT_SEPARATOR
) || mii
.dwItemData
== 0)
663 HeapFree(GetProcessHeap(), 0, (LPVOID
)mii
.dwItemData
);
670 COpenWithMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
674 ERR("This %p wId %x count %u verb %x\n", this, wId
, count
, LOWORD(lpici
->lpVerb
));
676 if (wId
< LOWORD(lpici
->lpVerb
))
679 if (wId
== LOWORD(lpici
->lpVerb
))
683 info
.pcszFile
= szPath
;
684 info
.oaifInFlags
= OAIF_ALLOW_REGISTRATION
| OAIF_REGISTER_EXT
| OAIF_EXEC
;
685 info
.pcszClass
= NULL
;
686 FreeMenuItemContext(hSubMenu
);
687 return SHOpenWithDialog(lpici
->hwnd
, &info
);
690 /* retrieve menu item info */
691 ZeroMemory(&mii
, sizeof(mii
));
692 mii
.cbSize
= sizeof(mii
);
693 mii
.fMask
= MIIM_DATA
| MIIM_FTYPE
;
695 if (GetMenuItemInfoW(hSubMenu
, LOWORD(lpici
->lpVerb
), TRUE
, &mii
))
697 POPEN_ITEM_CONTEXT pItemContext
= (POPEN_ITEM_CONTEXT
)mii
.dwItemData
;
700 /* launch item with specified app */
701 ExecuteOpenItem(pItemContext
, szPath
);
704 /* free menu item context */
705 FreeMenuItemContext(hSubMenu
);
710 COpenWithMenu::GetCommandString(UINT_PTR idCmd
, UINT uType
,
711 UINT
* pwReserved
, LPSTR pszName
, UINT cchMax
)
713 FIXME("%p %lu %u %p %p %u\n", this,
714 idCmd
, uType
, pwReserved
, pszName
, cchMax
);
719 HRESULT WINAPI
COpenWithMenu::HandleMenuMsg(
724 TRACE("This %p uMsg %x\n",this, uMsg
);
730 GetManufacturer(WCHAR
* szAppName
, POPEN_ITEM_CONTEXT pContext
)
737 LPLANGANDCODEPAGE lplangcode
;
742 static const WCHAR wFormat
[] = L
"\\StringFileInfo\\%04x%04x\\CompanyName";
743 static const WCHAR wTranslation
[] = L
"VarFileInfo\\Translation";
745 /* query version info size */
746 VerSize
= GetFileVersionInfoSizeW(szAppName
, &DummyHandle
);
749 pContext
->szManufacturer
[0] = 0;
753 /* allocate buffer */
754 pBuf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, VerSize
);
757 pContext
->szManufacturer
[0] = 0;
761 /* query version info */
762 if(!GetFileVersionInfoW(szAppName
, 0, VerSize
, pBuf
))
764 pContext
->szManufacturer
[0] = 0;
765 HeapFree(GetProcessHeap(), 0, pBuf
);
769 /* query lang code */
770 if(VerQueryValueW(pBuf
, const_cast<LPWSTR
>(wTranslation
), (LPVOID
*)&lplangcode
, &VerSize
))
772 /* FIXME find language from current locale / if not available,
774 * for now default to first available language
776 lang
= lplangcode
->lang
;
777 code
= lplangcode
->code
;
780 swprintf(szBuffer
, wFormat
, lang
, code
);
781 /* query manufacturer */
783 bResult
= VerQueryValueW(pBuf
, szBuffer
, (LPVOID
*)&pResult
, &VerSize
);
785 if (VerSize
&& bResult
&& pResult
)
786 wcscpy(pContext
->szManufacturer
, pResult
);
788 pContext
->szManufacturer
[0] = 0;
789 HeapFree(GetProcessHeap(), 0, pBuf
);
796 InsertOpenWithItem(POPEN_WITH_CONTEXT pContext
, WCHAR
* szAppName
)
799 POPEN_ITEM_CONTEXT pItemContext
;
802 WCHAR Buffer
[_MAX_FNAME
];
804 pItemContext
= (OPEN_ITEM_CONTEXT
*)HeapAlloc(GetProcessHeap(), 0, sizeof(OPEN_ITEM_CONTEXT
));
809 wcscpy(pItemContext
->szAppName
, szAppName
);
810 /* null terminate it */
811 pItemContext
->szAppName
[MAX_PATH
-1] = 0;
812 /* extract path name */
813 _wsplitpath(szAppName
, NULL
, NULL
, Buffer
, NULL
);
814 Offset
= wcsrchr(Buffer
, '.');
817 Buffer
[0] = towupper(Buffer
[0]);
821 ZeroMemory(&mii
, sizeof(mii
));
822 mii
.cbSize
= sizeof(mii
);
823 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
| MIIM_DATA
;
824 mii
.fType
= MFT_STRING
; //MFT_OWNERDRAW;
825 mii
.fState
= MFS_ENABLED
;
826 mii
.wID
= pContext
->idCmdFirst
;
827 mii
.dwTypeData
= Buffer
;
828 mii
.cch
= wcslen(Buffer
);
829 mii
.dwItemData
= (ULONG_PTR
)pItemContext
;
830 wcscpy(pItemContext
->szManufacturer
, Buffer
);
831 if (InsertMenuItemW(pContext
->hMenu
, -1, TRUE
, &mii
))
833 pContext
->idCmdFirst
++;
839 /* get default icon */
840 pItemContext
->hIcon
= ExtractIconW(shell32_hInstance
, szAppName
, 0);
841 /* get manufacturer */
842 GetManufacturer(pItemContext
->szAppName
, pItemContext
);
843 index
= SendMessageW(pContext
->hDlgCtrl
, LB_ADDSTRING
, 0, (LPARAM
)Buffer
);
845 SendMessageW(pContext
->hDlgCtrl
, LB_SETITEMDATA
, index
, (LPARAM
)pItemContext
);
850 AddItemFromProgIDList(POPEN_WITH_CONTEXT pContext
, HKEY hKey
)
852 FIXME("implement me :)))\n");
856 OpenMRUList(HKEY hKey
)
860 /* initialize mru list info */
861 info
.cbSize
= sizeof(info
);
863 info
.dwFlags
= MRU_STRING
;
865 info
.lpszSubKey
= L
"OpenWithList";
866 info
.lpfnCompare
= NULL
;
869 return CreateMRUListW(&info
);
873 AddItemFromMRUList(POPEN_WITH_CONTEXT pContext
, HKEY hKey
)
876 int nItem
, nCount
, nResult
;
877 WCHAR szBuffer
[MAX_PATH
];
880 hList
= OpenMRUList(hKey
);
885 nCount
= EnumMRUListW(hList
, -1, NULL
, 0);
887 for(nItem
= 0; nItem
< nCount
; nItem
++)
889 nResult
= EnumMRUListW(hList
, nItem
, szBuffer
, MAX_PATH
);
892 /* make sure its zero terminated */
893 szBuffer
[min(MAX_PATH
-1, nResult
)] = '\0';
895 if (!HideApplicationFromList(szBuffer
))
896 InsertOpenWithItem(pContext
, szBuffer
);
899 /* free the mru list */
906 LoadItemFromHKCR(POPEN_WITH_CONTEXT pContext
, const WCHAR
* szExt
)
910 WCHAR szBuffer
[MAX_PATH
+10];
914 static const WCHAR szOpenWithList
[] = L
"OpenWithList";
915 static const WCHAR szOpenWithProgIds
[] = L
"OpenWithProgIDs";
916 static const WCHAR szPerceivedType
[] = L
"PerceivedType";
917 static const WCHAR szSysFileAssoc
[] = L
"SystemFileAssociations\\%s";
919 /* check if extension exists */
920 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szExt
, 0, KEY_READ
| KEY_WRITE
, &hKey
) != ERROR_SUCCESS
)
923 if (RegGetValueW(hKey
, NULL
, L
"NoOpen", RRF_RT_REG_SZ
, NULL
, NULL
, &dwSize
) == ERROR_SUCCESS
)
925 /* display warning dialog */
926 pContext
->NoOpen
= TRUE
;
929 /* check if there is a directly available execute key */
930 if (RegOpenKeyExW(hKey
, L
"shell\\open\\command", 0, KEY_READ
, &hSubKey
) == ERROR_SUCCESS
)
932 DWORD dwBuffer
= sizeof(szBuffer
);
934 if (RegGetValueW(hSubKey
, NULL
, NULL
, RRF_RT_REG_SZ
, NULL
, (PVOID
)szBuffer
, &dwBuffer
) == ERROR_SUCCESS
)
936 WCHAR
* Ext
= wcsrchr(szBuffer
, ' ');
939 /* erase %1 or extra arguments */
942 if(!HideApplicationFromList(szBuffer
))
943 InsertOpenWithItem(pContext
, szBuffer
);
945 RegCloseKey(hSubKey
);
948 /* load items from HKCR\Ext\OpenWithList */
949 if (RegOpenKeyExW(hKey
, szOpenWithList
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hSubKey
) == ERROR_SUCCESS
)
951 AddItemFromMRUList(pContext
, hKey
);
952 RegCloseKey(hSubKey
);
955 /* load items from HKCR\Ext\OpenWithProgIDs */
956 if (RegOpenKeyExW(hKey
, szOpenWithProgIds
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hSubKey
) == ERROR_SUCCESS
)
958 AddItemFromProgIDList(pContext
, hSubKey
);
959 RegCloseKey(hSubKey
);
962 /* load items from SystemFileAssociations\Ext key */
963 swprintf(szResult
, szSysFileAssoc
, szExt
);
964 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szResult
, 0, KEY_READ
| KEY_WRITE
, &hSubKey
) == ERROR_SUCCESS
)
966 AddItemFromMRUList(pContext
, hSubKey
);
967 RegCloseKey(hSubKey
);
970 /* load additional items from referenced PerceivedType*/
971 dwSize
= sizeof(szBuffer
);
972 if (RegGetValueW(hKey
, NULL
, szPerceivedType
, RRF_RT_REG_SZ
, NULL
, szBuffer
, &dwSize
) != ERROR_SUCCESS
)
979 /* terminate it explictely */
981 swprintf(szResult
, szSysFileAssoc
, szBuffer
);
982 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szResult
, 0, KEY_READ
| KEY_WRITE
, &hSubKey
) == ERROR_SUCCESS
)
984 AddItemFromMRUList(pContext
, hSubKey
);
985 RegCloseKey(hSubKey
);
990 LoadItemFromHKCU(POPEN_WITH_CONTEXT pContext
, const WCHAR
* szExt
)
992 WCHAR szBuffer
[MAX_PATH
];
995 static const WCHAR szOpenWithProgIDs
[] = L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s\\OpenWithProgIDs";
996 static const WCHAR szOpenWithList
[] = L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s";
998 /* handle first progid lists */
999 swprintf(szBuffer
, szOpenWithProgIDs
, szExt
);
1000 if (RegOpenKeyExW(HKEY_CURRENT_USER
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
) == ERROR_SUCCESS
)
1002 AddItemFromProgIDList(pContext
, hKey
);
1006 /* now handle mru lists */
1007 swprintf(szBuffer
, szOpenWithList
, szExt
);
1008 if (RegOpenKeyExW(HKEY_CURRENT_USER
, szBuffer
, 0, KEY_READ
| KEY_WRITE
, &hKey
) == ERROR_SUCCESS
)
1010 AddItemFromMRUList(pContext
, hKey
);
1016 COpenWithMenu::SHEOW_LoadOpenWithItems(IDataObject
*pdtobj
)
1022 LPCITEMIDLIST pidl_folder
;
1023 LPCITEMIDLIST pidl_child
;
1027 static const WCHAR szShortCut
[] = { '.','l','n','k', 0 };
1029 fmt
.cfFormat
= RegisterClipboardFormatW(CFSTR_SHELLIDLIST
);
1031 fmt
.dwAspect
= DVASPECT_CONTENT
;
1033 fmt
.tymed
= TYMED_HGLOBAL
;
1035 hr
= pdtobj
->GetData(&fmt
, &medium
);
1039 ERR("IDataObject_GetData failed with 0x%x\n", hr
);
1043 /*assert(pida->cidl==1);*/
1044 pida
= (LPIDA
)GlobalLock(medium
.hGlobal
);
1046 pidl_folder
= (LPCITEMIDLIST
) ((LPBYTE
)pida
+pida
->aoffset
[0]);
1047 pidl_child
= (LPCITEMIDLIST
) ((LPBYTE
)pida
+pida
->aoffset
[1]);
1049 pidl
= ILCombine(pidl_folder
, pidl_child
);
1051 GlobalUnlock(medium
.hGlobal
);
1052 GlobalFree(medium
.hGlobal
);
1057 return E_OUTOFMEMORY
;
1059 if (_ILIsDesktop(pidl
) || _ILIsMyDocuments(pidl
) || _ILIsControlPanel(pidl
) || _ILIsNetHood(pidl
) ||
1060 _ILIsBitBucket(pidl
) || _ILIsDrive(pidl
) || _ILIsCPanelStruct(pidl
) || _ILIsFolder(pidl
) || _ILIsControlPanel(pidl
))
1062 TRACE("pidl is a folder\n");
1063 SHFree((void*)pidl
);
1067 if (!SHGetPathFromIDListW(pidl
, szPath
))
1069 SHFree((void*)pidl
);
1070 ERR("SHGetPathFromIDListW failed\n");
1074 SHFree((void*)pidl
);
1075 TRACE("szPath %s\n", debugstr_w(szPath
));
1077 if (GetBinaryTypeW(szPath
, &dwPath
))
1079 TRACE("path is a executable %x\n", dwPath
);
1083 szPtr
= wcsrchr(szPath
, '.');
1086 if (!_wcsicmp(szPtr
, szShortCut
))
1088 FIXME("pidl is a shortcut\n");
1096 COpenWithMenu::Initialize(LPCITEMIDLIST pidlFolder
,
1097 IDataObject
*pdtobj
, HKEY hkeyProgID
)
1099 TRACE("This %p\n", this);
1102 return E_INVALIDARG
;
1103 return SHEOW_LoadOpenWithItems(pdtobj
);
1106 HRESULT WINAPI
SHOpenWithDialog(
1108 const OPENASINFO
*poainfo
1115 if (poainfo
->pcszClass
== NULL
&& poainfo
->pcszFile
== NULL
)
1119 hwnd
= CreateDialogParam(shell32_hInstance
, MAKEINTRESOURCE(OPEN_WITH_PROGRAMM_DLG
), hwndParent
, OpenWithProgrammDlg
, (LPARAM
)poainfo
);
1122 ERR("Failed to create dialog\n");
1125 ShowWindow(hwnd
, SW_SHOWNORMAL
);
1127 while ((bRet
= GetMessage(&msg
, NULL
, 0, 0)) != 0)
1129 if (!IsWindow(hwnd
) || !IsDialogMessage(hwnd
, &msg
))
1131 TranslateMessage(&msg
);
1132 DispatchMessage(&msg
);