Author: janderwald Date: Thu Nov 1 23:54:46 2007 New Revision: 30052
URL: http://svn.reactos.org/svn/reactos?rev=30052&view=rev Log: - implement loading & executing of static context menu extensions
Modified: trunk/reactos/dll/win32/shell32/shv_item_cmenu.c
Modified: trunk/reactos/dll/win32/shell32/shv_item_cmenu.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/shv_item_... ============================================================================== --- trunk/reactos/dll/win32/shell32/shv_item_cmenu.c (original) +++ trunk/reactos/dll/win32/shell32/shv_item_cmenu.c Thu Nov 1 23:54:46 2007 @@ -43,6 +43,13 @@ /* ugly hack for cut&paste files */ BOOL fileMoving = FALSE;
+typedef struct _StaticShellEntry_ +{ + LPWSTR szVerb; + LPWSTR szCmd; + struct _StaticShellEntry_ * Next; +}StaticShellEntry, *PStaticShellEntry; + /************************************************************************** * IContextMenu Implementation */ @@ -58,6 +65,9 @@ IContextMenu ** ecmenu; UINT esize; UINT ecount; + PStaticShellEntry head; + UINT iIdSCMFirst; + UINT iIdSCMLast; UINT iIdSHEFirst; UINT iIdSHELast; SFGAOF rfg; @@ -66,7 +76,7 @@ UINT SH_EnumerateDynamicContextHandlerForKey(LPWSTR szFileClass, ItemCmImpl *This, IDataObject * pDataObj, LPITEMIDLIST pidlFolder); WCHAR *build_paths_list(LPCWSTR wszBasePath, int cidl, LPCITEMIDLIST *pidls); - +WCHAR *strdupW(LPWSTR str); static const IContextMenu2Vtbl cmvt;
/************************************************************************** @@ -353,6 +363,179 @@ TRACE("SH_LoadContextMenuHandlers first %x last %x\n", This->iIdSHEFirst, This->iIdSHELast); }
+void +SH_AddStaticEntry(ItemCmImpl * This, HKEY hKey, WCHAR *szVerb) +{ + WCHAR szBuffer[50]; + WCHAR szCmd[100]; + DWORD dwCmd, dwBuffer; + LONG result; + HKEY hSubKey; + PStaticShellEntry curEntry; + PStaticShellEntry lastEntry = NULL; + + wcscpy(szBuffer, szVerb); + wcscat(szBuffer, L"\command"); + + TRACE("szBuffer %s\n", debugstr_w(szBuffer)); + + result = RegOpenKeyExW(hKey, szBuffer, 0, KEY_READ, &hSubKey); + if (result != ERROR_SUCCESS) + { + TRACE("RegOpenKeyEx failed with 0x%x\n", result); + return; + } + dwCmd = sizeof(szCmd); + dwBuffer = 50; + result = RegEnumValueW(hSubKey, 0, szBuffer, &dwBuffer, 0, NULL, (LPBYTE)szCmd, &dwCmd); + RegCloseKey(hSubKey); + if (result != ERROR_SUCCESS) + { + TRACE("RegGetValueW failed with 0x%x\n", result); + return; + } + TRACE("SH_AddStaticEntry szBuffer %s szCmd %s\n", debugstr_w(szBuffer), debugstr_w(szCmd)); + + curEntry = This->head; + + while(curEntry) + { + if (!wcsicmp(curEntry->szVerb, szVerb)) + { + /* entry already exists */ + return; + } + lastEntry = curEntry; + curEntry->Next = curEntry; + } + + curEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry)); + if (curEntry) + { + curEntry->Next = NULL; + curEntry->szCmd = StrDupW(szCmd); + curEntry->szVerb = StrDupW(szVerb); + } + + if (lastEntry) + { + lastEntry->Next = curEntry; + } + else + { + This->head = curEntry; + } +} + +void +SH_AddStaticEntryForKey(ItemCmImpl * This, HKEY hKey) +{ + LONG result; + DWORD dwIndex; + WCHAR szName[40]; + DWORD dwName; + + TRACE("SH_AddStaticEntryForKey entered\n"); + + dwIndex = 0; + do + { + szName[0] = 0; + dwName = sizeof(szName) / sizeof(WCHAR); + result = RegEnumKeyExW(hKey, dwIndex, szName, &dwName, NULL, NULL, NULL, NULL); + szName[39] = 0; + if (result == ERROR_SUCCESS) + { + TRACE("szVerb %s\n", debugstr_w(szName)); + SH_AddStaticEntry(This, hKey, szName); + } + dwIndex++; + }while(result == ERROR_SUCCESS); +} + +void +SH_AddStaticEntryForFileClass(ItemCmImpl * This, WCHAR * szExt) +{ + WCHAR szBuffer[100]; + HKEY hKey; + LONG result; + DWORD dwBuffer; + + TRACE("SH_AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt)); + + wcscpy(szBuffer, szExt); + wcscat(szBuffer, L"\shell"); + result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey); + if (result == ERROR_SUCCESS) + { + SH_AddStaticEntryForKey(This, hKey); + RegCloseKey(hKey); + } + + dwBuffer = sizeof(szBuffer); + result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, NULL, RRF_RT_REG_SZ, NULL, (LPBYTE)szBuffer, &dwBuffer); + if (result == ERROR_SUCCESS) + { + wcscat(szBuffer, L"\shell"); + TRACE("szBuffer %s\n", debugstr_w(szBuffer)); + + result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey); + if (result == ERROR_SUCCESS) + { + SH_AddStaticEntryForKey(This, hKey); + RegCloseKey(hKey); + } + } + + strcpyW(szBuffer, "SystemFileAssociations\"); + dwBuffer = sizeof(szBuffer) - strlenW(szBuffer) * sizeof(WCHAR); + result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, L"PerceivedType", RRF_RT_REG_SZ, NULL, (LPBYTE)&szBuffer[23], &dwBuffer); + if (result == ERROR_SUCCESS) + { + wcscat(szBuffer, L"\shell"); + TRACE("szBuffer %s\n", debugstr_w(szBuffer)); + + result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey); + if (result == ERROR_SUCCESS) + { + SH_AddStaticEntryForKey(This, hKey); + RegCloseKey(hKey); + } + } + RegCloseKey(hKey); +} +UINT +SH_AddStaticEntryToMenu(HMENU hMenu, UINT indexMenu, ItemCmImpl * This) +{ + MENUITEMINFOW mii; + PStaticShellEntry curEntry; + + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA; + mii.fType = MFT_STRING; + mii.fState = MFS_ENABLED | MFS_DEFAULT; + mii.wID = 0x4000; + This->iIdSCMFirst = mii.wID; + + curEntry = This->head; + + while(curEntry) + { + /* FIXME + * load localized verbs if its an open edit find print printto openas properties verb + */ + + mii.dwTypeData = curEntry->szVerb; + mii.cch = strlenW(mii.dwTypeData); + InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii); + mii.fState = MFS_ENABLED; + mii.wID++; + curEntry = curEntry->Next; + } + This->iIdSCMLast = mii.wID - 1; + return indexMenu; +} + const char * GetLocalizedString(HMENU hMenu, UINT wID, const char * sDefault, char * sResult) { MENUITEMINFOA mii; @@ -395,6 +578,7 @@ USHORT lastindex = 0; HMENU hLocalMenu; char sBuffer[100]; + WCHAR szExt[10];
static const char sExplore[] = { '&','E','x','p','l','o','r','e',0 }; static const char sCopy[] = { '&','C','o','p','y',0 }; @@ -408,6 +592,22 @@ TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",This, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
hLocalMenu = LoadMenuW(shell32_hInstance, szSHVFile); + + if (_ILGetExtension(This->apidl[0], &sBuffer[1], sizeof(sBuffer)-1)) + { + sBuffer[0] = '.'; + MultiByteToWideChar( CP_ACP, 0, sBuffer, -1, (LPWSTR)szExt, 10); + SH_AddStaticEntryForFileClass(This, szExt); + indexMenu = SH_AddStaticEntryToMenu(hmenu, indexMenu, This); + } + + pDataObj = IDataObject_Constructor(NULL, This->pidl, This->apidl, This->cidl); + if (pDataObj) + { + SH_LoadContextMenuHandlers(This, pDataObj, hmenu, indexMenu); + IDataObject_Release(pDataObj); + } +
if (idCmdFirst != 0) FIXME("We should use idCmdFirst=%d and idCmdLast=%d for command ids\n", idCmdFirst, idCmdLast); @@ -460,12 +660,7 @@
lastindex = FCIDM_SHVIEWLAST; } - pDataObj = IDataObject_Constructor(NULL, This->pidl, This->apidl, This->cidl); - if (pDataObj) - { - SH_LoadContextMenuHandlers(This, pDataObj, hmenu, indexMenu); - IDataObject_Release(pDataObj); - } + if (hLocalMenu) { DestroyMenu(hLocalMenu); @@ -706,7 +901,84 @@ } } HRESULT -DoShellExtensions(ItemCmImpl *This, LPCMINVOKECOMMANDINFO lpcmi) +DoStaticShellExtensions(ItemCmImpl *This, LPCMINVOKECOMMANDINFO lpcmi) +{ + UINT i; + WCHAR szTarget[MAX_PATH]; + WCHAR szTemp[MAX_PATH]; + WCHAR *ptr, *szCmd; + PStaticShellEntry curEntry; + LPITEMIDLIST pidl; + STARTUPINFOW sInfo; + PROCESS_INFORMATION pi; + + static const WCHAR szP1[] = { '%', '1', 0 }; + + TRACE("DoStaticShellExtensions entered with lpVerb %x first %x last %x\n", LOWORD(lpcmi->lpVerb), This->iIdSCMFirst, This->iIdSCMLast); + + i = This->iIdSCMFirst; + curEntry = This->head; + + while(curEntry) + { + if (i == LOWORD(lpcmi->lpVerb)) + break; + + i++; + curEntry = curEntry->Next; + } + + if (!curEntry) + { + ERR("unexpected\n"); + return E_UNEXPECTED; + } + + ExpandEnvironmentStringsW(curEntry->szCmd, szTarget, MAX_PATH); + + ptr = wcsstr(szTarget, szP1); + if (ptr) + { + ptr[1] = 's'; + pidl = ILCombine(This->pidl, This->apidl[0]); + if (pidl) + { + WCHAR szPath[MAX_PATH]; + if (SHGetPathFromIDListW(pidl, szPath)) + { + sprintfW(szTemp, szTarget, szPath); + } + SHFree(pidl); + } + else + { + ptr[0] = 0; + } + ptr = szTemp; + } + else + { + ptr = szTarget; + } + + ZeroMemory(&sInfo, sizeof(sInfo)); + sInfo.cb = sizeof(sizeof(sInfo)); + szCmd = wcsdup(ptr); + + if (!szCmd) + return E_OUTOFMEMORY; + + if (CreateProcessW(NULL, szCmd, NULL, NULL,FALSE,0,NULL,NULL,&sInfo, &pi)) + { + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + } + free(szCmd); + return S_OK; +} + +HRESULT +DoDynamicShellExtensions(ItemCmImpl *This, LPCMINVOKECOMMANDINFO lpcmi) { HRESULT hResult = NOERROR; UINT i; @@ -739,7 +1011,7 @@ if (lpcmi->cbSize != sizeof(CMINVOKECOMMANDINFO)) FIXME("Is an EX structure\n");
- TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd); + TRACE("ISvItemCm_fnInvokeCommand (%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);
if( HIWORD(lpcmi->lpVerb)==0 && LOWORD(lpcmi->lpVerb) > FCIDM_SHVIEWLAST) { @@ -782,8 +1054,14 @@ default: if (LOWORD(lpcmi->lpVerb) >= This->iIdSHEFirst && LOWORD(lpcmi->lpVerb) <= This->iIdSHELast) { - return DoShellExtensions(This, lpcmi); + return DoDynamicShellExtensions(This, lpcmi); } + + if (LOWORD(lpcmi->lpVerb) >= This->iIdSCMFirst && LOWORD(lpcmi->lpVerb) <= This->iIdSCMLast) + { + return DoStaticShellExtensions(This, lpcmi); + } + FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb)); } }