OSDN Git Service

Cleanup 'look and feel' settings page.
[tortoisegit/TortoiseGitJp.git] / src / TortoiseShell / ContextMenu.cpp
1 // TortoiseGit - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2008 - TortoiseGit\r
4 \r
5 // This program is free software; you can redistribute it and/or\r
6 // modify it under the terms of the GNU General Public License\r
7 // as published by the Free Software Foundation; either version 2\r
8 // of the License, or (at your option) any later version.\r
9 \r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 \r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, write to the Free Software Foundation,\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 //\r
19 #include "stdafx.h"\r
20 #include "ShellExt.h"\r
21 #include "ItemIDList.h"\r
22 #include "PreserveChdir.h"\r
23 #include "UnicodeUtils.h"\r
24 //#include "GitProperties.h"\r
25 #include "GitStatus.h"\r
26 #include "TGitPath.h"\r
27 \r
28 #define GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])\r
29 #define GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])\r
30 \r
31 int g_shellidlist=RegisterClipboardFormat(CFSTR_SHELLIDLIST);\r
32 \r
33 CShellExt::MenuInfo CShellExt::menuInfo[] =\r
34 {       \r
35         { ShellMenuClone,                                               MENUCLONE,                      IDI_CLONE,                              IDS_MENUCLONE,                  IDS_MENUDESCCHECKOUT,\r
36         ITEMIS_FOLDER, ITEMIS_INSVN|ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0, 0 },\r
37 \r
38         { ShellMenuPull,                                                MENUPULL,                       IDI_PULL,                               IDS_MENUPULL,                   IDS_MENUPULL,\r
39         ITEMIS_INSVN, 0, ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0 },\r
40 \r
41         { ShellMenuFetch,                                               MENUFETCH,                      IDI_PULL,                               IDS_MENUFETCH,                  IDS_MENUFETCH,\r
42         ITEMIS_INSVN, 0, ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0 },\r
43 \r
44         { ShellMenuPush,                                                MENUPUSH,                       IDI_PUSH,                               IDS_MENUPUSH,                   IDS_MENUPULL,\r
45         ITEMIS_INSVN, 0, ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0 },\r
46 \r
47 //      { ShellMenuCheckout,                                    MENUCHECKOUT,           IDI_CHECKOUT,                   IDS_MENUCHECKOUT,                       IDS_MENUDESCCHECKOUT,\r
48 //      ITEMIS_FOLDER, ITEMIS_INSVN|ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0, 0 },\r
49 \r
50 //      { ShellMenuUpdate,                                              MENUUPDATE,                     IDI_UPDATE,                             IDS_MENUUPDATE,                         IDS_MENUDESCUPDATE,                             \r
51 //      ITEMIS_INSVN,   ITEMIS_ADDED, ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0 },\r
52 \r
53         { ShellMenuCommit,                                              MENUCOMMIT,                     IDI_COMMIT,                             IDS_MENUCOMMIT,                         IDS_MENUDESCCOMMIT,\r
54         ITEMIS_INSVN, 0, ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0 },\r
55 \r
56         { ShellSeparator, 0, 0, 0, 0, 0, 0, 0, 0},\r
57 \r
58         { ShellMenuDiff,                                                MENUDIFF,                       IDI_DIFF,                               IDS_MENUDIFF,                           IDS_MENUDESCDIFF,\r
59         ITEMIS_INSVN|ITEMIS_ONLYONE, ITEMIS_FOLDER|ITEMIS_NORMAL, ITEMIS_TWO, 0, 0, 0, 0, 0 },\r
60 \r
61         { ShellMenuPrevDiff,                                    MENUPREVDIFF,                   IDI_DIFF,                               IDS_MENUPREVDIFF,                       IDS_MENUDESCPREVDIFF,\r
62         ITEMIS_INSVN|ITEMIS_ONLYONE, ITEMIS_FOLDER, 0, 0, 0, 0, 0, 0 },\r
63 \r
64 //      { ShellMenuUrlDiff,                                             MENUURLDIFF,            IDI_DIFF,                               IDS_MENUURLDIFF,                        IDS_MENUDESCURLDIFF,\r
65 //      ITEMIS_INSVN|ITEMIS_ONLYONE|ITEMIS_EXTENDED, 0, ITEMIS_FOLDERINSVN|ITEMIS_EXTENDED|ITEMIS_ONLYONE, 0, 0, 0, 0, 0 },\r
66 \r
67         { ShellMenuLog,                                                 MENULOG,                        IDI_LOG,                                IDS_MENULOG,                            IDS_MENUDESCLOG,\r
68         ITEMIS_INSVN|ITEMIS_ONLYONE, ITEMIS_ADDED, ITEMIS_FOLDER|ITEMIS_FOLDERINSVN|ITEMIS_ONLYONE, ITEMIS_ADDED, ITEMIS_FOLDERINSVN|ITEMIS_ONLYONE, ITEMIS_ADDED, 0, 0 },\r
69 \r
70 //      { ShellMenuRepoBrowse,                                  MENUREPOBROWSE,         IDI_REPOBROWSE,                 IDS_MENUREPOBROWSE,                     IDS_MENUDESCREPOBROWSE,\r
71 //      ITEMIS_ONLYONE, 0, ITEMIS_FOLDERINSVN|ITEMIS_ONLYONE, 0, 0, 0, 0, 0 },\r
72 \r
73         { ShellMenuShowChanged,                                 MENUSHOWCHANGED,        IDI_SHOWCHANGED,                IDS_MENUSHOWCHANGED,            IDS_MENUDESCSHOWCHANGED,\r
74         ITEMIS_INSVN|ITEMIS_ONLYONE, 0, ITEMIS_FOLDER|ITEMIS_FOLDERINSVN|ITEMIS_ONLYONE, 0, 0, 0, 0, 0},\r
75 \r
76 //      { ShellMenuRevisionGraph,                               MENUREVISIONGRAPH,      IDI_REVISIONGRAPH,              IDS_MENUREVISIONGRAPH,          IDS_MENUDESCREVISIONGRAPH,\r
77 //      ITEMIS_INSVN|ITEMIS_ONLYONE, ITEMIS_ADDED, ITEMIS_FOLDER|ITEMIS_FOLDERINSVN|ITEMIS_ONLYONE, ITEMIS_ADDED, 0, 0, 0, 0},\r
78 \r
79         { ShellSeparator, 0, 0, 0, 0, 0, 0, 0, 0},\r
80 \r
81         { ShellMenuConflictEditor,                              MENUCONFLICTEDITOR,     IDI_CONFLICT,                   IDS_MENUCONFLICT,                       IDS_MENUDESCCONFLICT,\r
82         ITEMIS_INSVN|ITEMIS_CONFLICTED, ITEMIS_FOLDER, 0, 0, 0, 0, 0, 0 },\r
83 \r
84 //      { ShellMenuResolve,                                             MENURESOLVE,            IDI_RESOLVE,                    IDS_MENURESOLVE,                        IDS_MENUDESCRESOLVE,\r
85 //      ITEMIS_INSVN|ITEMIS_CONFLICTED, 0, ITEMIS_INSVN|ITEMIS_FOLDER, 0, ITEMIS_FOLDERINSVN, 0, 0, 0 },\r
86 \r
87 //      { ShellMenuUpdateExt,                                   MENUUPDATEEXT,          IDI_UPDATE,                             IDS_MENUUPDATEEXT,                      IDS_MENUDESCUPDATEEXT,\r
88 //      ITEMIS_INSVN, ITEMIS_ADDED, ITEMIS_FOLDERINSVN, ITEMIS_ADDED, 0, 0, 0, 0 },\r
89 \r
90         { ShellMenuRename,                                              MENURENAME,                     IDI_RENAME,                             IDS_MENURENAME,                         IDS_MENUDESCRENAME,\r
91         ITEMIS_INSVN|ITEMIS_ONLYONE|ITEMIS_INVERSIONEDFOLDER, 0, 0, 0, 0, 0, 0, 0 },\r
92 \r
93         { ShellMenuRemove,                                              MENUREMOVE,                     IDI_DELETE,                             IDS_MENUREMOVE,                         IDS_MENUDESCREMOVE,\r
94         ITEMIS_INSVN|ITEMIS_INVERSIONEDFOLDER, ITEMIS_ADDED, 0, 0, 0, 0, 0, 0 },\r
95 \r
96         { ShellMenuRemoveKeep,                                  MENUREMOVE,                     IDI_DELETE,                             IDS_MENUREMOVEKEEP,                     IDS_MENUDESCREMOVEKEEP,\r
97         ITEMIS_INSVN|ITEMIS_INVERSIONEDFOLDER|ITEMIS_EXTENDED, ITEMIS_ADDED, 0, 0, 0, 0, 0, 0 },\r
98 \r
99         { ShellMenuRevert,                                              MENUREVERT,                     IDI_REVERT,                             IDS_MENUREVERT,                         IDS_MENUDESCREVERT,\r
100         ITEMIS_INSVN, ITEMIS_NORMAL|ITEMIS_ADDED, ITEMIS_FOLDERINSVN, ITEMIS_ADDED, 0, 0, 0, 0 },\r
101 \r
102         { ShellMenuRevert,                                              MENUREVERT,                     IDI_REVERT,                             IDS_MENUUNDOADD,                        IDS_MENUDESCUNDOADD,\r
103         ITEMIS_ADDED, ITEMIS_NORMAL, ITEMIS_FOLDERINSVN|ITEMIS_ADDED, 0, 0, 0, 0, 0 },\r
104 \r
105         { ShellMenuDelUnversioned,                              MENUDELUNVERSIONED,     IDI_DELUNVERSIONED,             IDS_MENUDELUNVERSIONED,         IDS_MENUDESCDELUNVERSIONED,\r
106         ITEMIS_FOLDER|ITEMIS_INSVN|ITEMIS_EXTENDED, 0, ITEMIS_FOLDER|ITEMIS_FOLDERINSVN|ITEMIS_EXTENDED, 0, 0, 0, 0, 0 },\r
107 \r
108         { ShellMenuCleanup,                                             MENUCLEANUP,            IDI_CLEANUP,                    IDS_MENUCLEANUP,                        IDS_MENUDESCCLEANUP,\r
109         ITEMIS_INSVN|ITEMIS_FOLDER, 0, ITEMIS_FOLDERINSVN|ITEMIS_FOLDER, 0, 0, 0, 0, 0 },\r
110 \r
111 //      { ShellMenuLock,                                                MENULOCK,                       IDI_LOCK,                               IDS_MENU_LOCK,                          IDS_MENUDESC_LOCK,\r
112 //      ITEMIS_INSVN, ITEMIS_LOCKED|ITEMIS_ADDED, ITEMIS_FOLDERINSVN, ITEMIS_LOCKED|ITEMIS_ADDED, 0, 0, 0, 0 },\r
113 \r
114 //      { ShellMenuUnlock,                                              MENUUNLOCK,                     IDI_UNLOCK,                             IDS_MENU_UNLOCK,                        IDS_MENUDESC_UNLOCK,\r
115 //      ITEMIS_INSVN|ITEMIS_LOCKED, 0, ITEMIS_FOLDER|ITEMIS_INSVN, 0, ITEMIS_FOLDERINSVN, 0, 0, 0 },\r
116 \r
117 //      { ShellMenuUnlockForce,                                 MENUUNLOCK,                     IDI_UNLOCK,                             IDS_MENU_UNLOCKFORCE,           IDS_MENUDESC_UNLOCKFORCE,\r
118 //      ITEMIS_INSVN|ITEMIS_LOCKED, 0, ITEMIS_FOLDER|ITEMIS_INSVN|ITEMIS_EXTENDED, 0, 0, 0, 0, 0 },\r
119 \r
120         { ShellSeparator, 0, 0, 0, 0, 0, 0, 0, 0},\r
121 \r
122 //      { ShellMenuCopy,                                                MENUCOPY,                       IDI_COPY,                               IDS_MENUBRANCH,                         IDS_MENUDESCCOPY,\r
123 //      ITEMIS_INSVN|ITEMIS_ONLYONE, ITEMIS_ADDED, ITEMIS_FOLDER|ITEMIS_FOLDERINSVN|ITEMIS_ONLYONE, 0, 0, 0, 0, 0 },\r
124 \r
125         { ShellMenuSwitch,                                              MENUSWITCH,                     IDI_SWITCH,                             IDS_MENUSWITCH,                         IDS_MENUDESCSWITCH,\r
126         ITEMIS_INSVN|ITEMIS_ONLYONE, ITEMIS_ADDED, ITEMIS_FOLDER|ITEMIS_FOLDERINSVN|ITEMIS_ONLYONE, 0, 0, 0, 0, 0 },\r
127 \r
128         { ShellMenuMerge,                                               MENUMERGE,                      IDI_MERGE,                              IDS_MENUMERGE,                          IDS_MENUDESCMERGE,\r
129         ITEMIS_INSVN|ITEMIS_ONLYONE, ITEMIS_ADDED, ITEMIS_FOLDER|ITEMIS_FOLDERINSVN|ITEMIS_ONLYONE, 0, 0, 0, 0, 0 },\r
130         { ShellMenuMergeAll,                                    MENUMERGEALL,           IDI_MERGE,                              IDS_MENUMERGEALL,                       IDS_MENUDESCMERGEALL,\r
131         ITEMIS_INSVN|ITEMIS_ONLYONE|ITEMIS_EXTENDED, ITEMIS_ADDED, ITEMIS_FOLDER|ITEMIS_FOLDERINSVN|ITEMIS_ONLYONE|ITEMIS_EXTENDED, 0, 0, 0, 0, 0 },\r
132 \r
133         { ShellMenuBranch,                                              MENUCOPY,                       IDI_COPY,                               IDS_MENUBRANCH,                         IDS_MENUDESCCOPY,\r
134         ITEMIS_INSVN, 0, ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0 },\r
135         { ShellMenuTag,                                                 MENUTAG,                        IDI_TAG,                                IDS_MENUTAG,                            IDS_MENUDESCCOPY,\r
136         ITEMIS_INSVN, 0, ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0 },\r
137 \r
138         { ShellMenuExport,                                              MENUEXPORT,                     IDI_EXPORT,                             IDS_MENUEXPORT,                         IDS_MENUDESCEXPORT,\r
139         ITEMIS_INSVN, 0, ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0 },\r
140 \r
141 //      { ShellMenuRelocate,                                    MENURELOCATE,           IDI_RELOCATE,                   IDS_MENURELOCATE,                       IDS_MENUDESCRELOCATE,\r
142 //      ITEMIS_INSVN|ITEMIS_FOLDER|ITEMIS_FOLDERINSVN|ITEMIS_ONLYONE, 0, ITEMIS_FOLDERINSVN|ITEMIS_ONLYONE, 0, 0, 0, 0, 0 },\r
143 \r
144         { ShellSeparator, 0, 0, 0, 0, 0, 0, 0, 0},\r
145 \r
146         { ShellMenuCreateRepos,                                 MENUCREATEREPOS,        IDI_CREATEREPOS,                IDS_MENUCREATEREPOS,            IDS_MENUDESCCREATEREPOS,\r
147         ITEMIS_FOLDER, ITEMIS_INSVN|ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0, 0 },\r
148 \r
149         { ShellMenuAdd,                                                 MENUADD,                        IDI_ADD,                                IDS_MENUADD,                            IDS_MENUDESCADD,\r
150         ITEMIS_INVERSIONEDFOLDER, ITEMIS_INSVN, ITEMIS_INSVN|ITEMIS_FOLDER, 0, ITEMIS_IGNORED, 0, ITEMIS_DELETED, ITEMIS_FOLDER|ITEMIS_ONLYONE },\r
151 \r
152 //      { ShellMenuAddAsReplacement,                    MENUADD,                        IDI_ADD,                                IDS_MENUADDASREPLACEMENT,       IDS_MENUADDASREPLACEMENT,\r
153 //      ITEMIS_DELETED|ITEMIS_ONLYONE, ITEMIS_FOLDER, 0, 0, 0, 0, 0, 0 },\r
154 \r
155 //      { ShellMenuImport,                                              MENUIMPORT,                     IDI_IMPORT,                             IDS_MENUIMPORT,                         IDS_MENUDESCIMPORT,\r
156 //      ITEMIS_FOLDER, ITEMIS_INSVN, 0, 0, 0, 0, 0, 0 },\r
157 \r
158         { ShellMenuBlame,                                               MENUBLAME,                      IDI_BLAME,                              IDS_MENUBLAME,                          IDS_MENUDESCBLAME,\r
159         ITEMIS_NORMAL|ITEMIS_ONLYONE, ITEMIS_FOLDER|ITEMIS_ADDED, 0, 0, 0, 0, 0, 0 },\r
160         // TODO: original code is ITEMIS_INSVN|ITEMIS_ONLYONE, makes sense to only allow blaming of versioned files\r
161         //       why was this changed, is this related to GitStatus?\r
162 \r
163         { ShellMenuIgnoreSub,                                   MENUIGNORE,                     IDI_IGNORE,                             IDS_MENUIGNORE,                         IDS_MENUDESCIGNORE,\r
164         ITEMIS_INVERSIONEDFOLDER, ITEMIS_IGNORED|ITEMIS_INSVN, 0, 0, 0, 0, 0, 0 },\r
165 \r
166         { ShellMenuUnIgnoreSub,                                 MENUIGNORE,                     IDI_IGNORE,                             IDS_MENUUNIGNORE,                       IDS_MENUDESCUNIGNORE,\r
167         ITEMIS_IGNORED, 0, 0, 0, 0, 0, 0, 0 },\r
168 \r
169         { ShellSeparator, 0, 0, 0, 0, 0, 0, 0, 0},\r
170 \r
171 //      { ShellMenuCherryPick,                                  MENUCHERRYPICK,         IDI_CREATEPATCH,                IDS_MENUCHERRYPICK,             IDS_MENUDESCCREATEPATCH,\r
172 //      ITEMIS_INSVN, ITEMIS_NORMAL, ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0 },\r
173 \r
174         { ShellMenuFormatPatch,                                 MENUFORMATPATCH,        IDI_CREATEPATCH,                IDS_MENUFORMATPATCH,            IDS_MENUDESCCREATEPATCH,\r
175         ITEMIS_INSVN, ITEMIS_NORMAL, ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0 },\r
176 \r
177         { ShellMenuImportPatch,                                 MENUIMPORTPATCH,        IDI_PATCH,                              IDS_MENUIMPORTPATCH,            IDS_MENUDESCCREATEPATCH,\r
178         ITEMIS_INSVN, ITEMIS_NORMAL, ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0 },\r
179 \r
180 \r
181         { ShellMenuCreatePatch,                                 MENUCREATEPATCH,        IDI_CREATEPATCH,                IDS_MENUCREATEPATCH,            IDS_MENUDESCCREATEPATCH,\r
182         ITEMIS_INSVN, ITEMIS_NORMAL, ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0 },\r
183 \r
184         { ShellMenuApplyPatch,                                  MENUAPPLYPATCH,         IDI_PATCH,                              IDS_MENUAPPLYPATCH,                     IDS_MENUDESCAPPLYPATCH,\r
185         ITEMIS_INSVN|ITEMIS_FOLDER|ITEMIS_FOLDERINSVN, ITEMIS_ADDED, ITEMIS_ONLYONE|ITEMIS_PATCHFILE, 0, ITEMIS_FOLDERINSVN, ITEMIS_ADDED, 0, 0 },\r
186 \r
187         { ShellMenuProperties,                                  MENUPROPERTIES,         IDI_PROPERTIES,                 IDS_MENUPROPERTIES,                     IDS_MENUDESCPROPERTIES,\r
188         ITEMIS_INSVN, 0, ITEMIS_FOLDERINSVN, 0, 0, 0, 0, 0 },\r
189 \r
190         { ShellSeparator, 0, 0, 0, 0, 0, 0, 0, 0},\r
191 //      { ShellMenuClipPaste,                                   MENUCLIPPASTE,          IDI_CLIPPASTE,                  IDS_MENUCLIPPASTE,                      IDS_MENUDESCCLIPPASTE,\r
192 //      ITEMIS_INSVN|ITEMIS_FOLDER|ITEMIS_PATHINCLIPBOARD, 0, 0, 0, 0, 0, 0, 0 },\r
193 \r
194         { ShellSeparator, 0, 0, 0, 0, 0, 0, 0, 0},\r
195 \r
196         { ShellMenuSettings,                                    MENUSETTINGS,           IDI_SETTINGS,                   IDS_MENUSETTINGS,                       IDS_MENUDESCSETTINGS,\r
197         ITEMIS_FOLDER, 0, 0, ITEMIS_FOLDER, 0, 0, 0, 0 },\r
198         { ShellMenuHelp,                                                MENUHELP,                       IDI_HELP,                               IDS_MENUHELP,                           IDS_MENUDESCHELP,\r
199         ITEMIS_FOLDER, 0, 0, ITEMIS_FOLDER, 0, 0, 0, 0 },\r
200         { ShellMenuAbout,                                               MENUABOUT,                      IDI_ABOUT,                              IDS_MENUABOUT,                          IDS_MENUDESCABOUT,\r
201         ITEMIS_FOLDER, 0, 0, ITEMIS_FOLDER, 0, 0, 0, 0 },\r
202 \r
203         // the sub menus - they're not added like the the commands, therefore the menu ID is zero\r
204         // but they still need to be in here, because we use the icon and string information anyway.\r
205         { ShellSubMenu,                                                 NULL,                           IDI_APP,                                IDS_MENUSUBMENU,                        0,\r
206         0, 0, 0, 0, 0, 0, 0, 0 },\r
207         { ShellSubMenuFile,                                             NULL,                           IDI_MENUFILE,                   IDS_MENUSUBMENU,                        0,\r
208         0, 0, 0, 0, 0, 0, 0, 0 },\r
209         { ShellSubMenuFolder,                                   NULL,                           IDI_MENUFOLDER,                 IDS_MENUSUBMENU,                        0,\r
210         0, 0, 0, 0, 0, 0, 0, 0 },\r
211         { ShellSubMenuLink,                                             NULL,                           IDI_MENULINK,                   IDS_MENUSUBMENU,                        0,\r
212         0, 0, 0, 0, 0, 0, 0, 0 },\r
213         { ShellSubMenuMultiple,                                 NULL,                           IDI_MENUMULTIPLE,               IDS_MENUSUBMENU,                        0,\r
214         0, 0, 0, 0, 0, 0, 0, 0 },\r
215         // mark the last entry to tell the loop where to stop iterating over this array\r
216         { ShellMenuLastEntry,                                   0,                                      0,                                              0,                                                      0,\r
217         0, 0, 0, 0, 0, 0, 0, 0 },\r
218 };\r
219 \r
220 \r
221 STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pIDFolder,\r
222                                    LPDATAOBJECT pDataObj,\r
223                                    HKEY /* hRegKey */)\r
224 {\r
225 \r
226         ATLTRACE("Shell :: Initialize\n");\r
227         PreserveChdir preserveChdir;\r
228         files_.clear();\r
229         folder_.erase();\r
230         uuidSource.erase();\r
231         uuidTarget.erase();\r
232         itemStates = 0;\r
233         itemStatesFolder = 0;\r
234         stdstring statuspath;\r
235         git_wc_status_kind fetchedstatus = git_wc_status_none;\r
236         // get selected files/folders\r
237         if (pDataObj)\r
238         {\r
239                 STGMEDIUM medium;\r
240                 FORMATETC fmte = {(CLIPFORMAT)g_shellidlist,\r
241                         (DVTARGETDEVICE FAR *)NULL, \r
242                         DVASPECT_CONTENT, \r
243                         -1, \r
244                         TYMED_HGLOBAL};\r
245                 HRESULT hres = pDataObj->GetData(&fmte, &medium);\r
246 \r
247                 if (SUCCEEDED(hres) && medium.hGlobal)\r
248                 {\r
249                         if (m_State == FileStateDropHandler)\r
250                         {\r
251 \r
252                                 FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };\r
253                                 STGMEDIUM stg = { TYMED_HGLOBAL };\r
254                                 if ( FAILED( pDataObj->GetData ( &etc, &stg )))\r
255                                 {\r
256                                         ReleaseStgMedium ( &medium );\r
257                                         return E_INVALIDARG;\r
258                                 }\r
259 \r
260 \r
261                                 HDROP drop = (HDROP)GlobalLock(stg.hGlobal);\r
262                                 if ( NULL == drop )\r
263                                 {\r
264                                         ReleaseStgMedium ( &stg );\r
265                                         ReleaseStgMedium ( &medium );\r
266                                         return E_INVALIDARG;\r
267                                 }\r
268 \r
269                                 int count = DragQueryFile(drop, (UINT)-1, NULL, 0);\r
270                                 if (count == 1)\r
271                                         itemStates |= ITEMIS_ONLYONE;\r
272                                 for (int i = 0; i < count; i++)\r
273                                 {\r
274                                         // find the path length in chars\r
275                                         UINT len = DragQueryFile(drop, i, NULL, 0);\r
276                                         if (len == 0)\r
277                                                 continue;\r
278                                         TCHAR * szFileName = new TCHAR[len+1];\r
279                                         if (0 == DragQueryFile(drop, i, szFileName, len+1))\r
280                                         {\r
281                                                 delete [] szFileName;\r
282                                                 continue;\r
283                                         }\r
284                                         stdstring str = stdstring(szFileName);\r
285                                         delete [] szFileName;\r
286                                         if ((str.empty() == false)&&(g_ShellCache.IsContextPathAllowed(szFileName)))\r
287                                         {\r
288                                                 if (itemStates & ITEMIS_ONLYONE)\r
289                                                 {\r
290                                                         CTGitPath strpath;\r
291                                                         strpath.SetFromWin(str.c_str());\r
292                                                         itemStates |= (strpath.GetFileExtension().CompareNoCase(_T(".diff"))==0) ? ITEMIS_PATCHFILE : 0;\r
293                                                         itemStates |= (strpath.GetFileExtension().CompareNoCase(_T(".patch"))==0) ? ITEMIS_PATCHFILE : 0;\r
294                                                 }\r
295                                                 files_.push_back(str);\r
296                                                 if (i == 0)\r
297                                                 {\r
298                                                         //get the Subversion status of the item\r
299                                                         git_wc_status_kind status = git_wc_status_none;\r
300                                                         CTGitPath askedpath;\r
301                                                         askedpath.SetFromWin(str.c_str());\r
302                                                         try\r
303                                                         {\r
304                                                                 GitStatus stat;\r
305                                                                 stat.GetStatus(CTGitPath(str.c_str()), false, true, true);\r
306                                                                 if (stat.status)\r
307                                                                 {\r
308                                                                         statuspath = str;\r
309                                                                         status = GitStatus::GetMoreImportant(stat.status->text_status, stat.status->prop_status);\r
310                                                                         fetchedstatus = status;\r
311                                                                         //if ((stat.status->entry)&&(stat.status->entry->lock_token))\r
312                                                                         //      itemStates |= (stat.status->entry->lock_token[0] != 0) ? ITEMIS_LOCKED : 0;\r
313                                                                         if ( askedpath.IsDirectory() )//if ((stat.status->entry)&&(stat.status->entry->kind == git_node_dir))\r
314                                                                         {\r
315                                                                                 itemStates |= ITEMIS_FOLDER;\r
316                                                                                 if ((status != git_wc_status_unversioned)&&(status != git_wc_status_ignored)&&(status != git_wc_status_none))\r
317                                                                                         itemStates |= ITEMIS_FOLDERINSVN;\r
318                                                                         }\r
319                                                                         //if ((stat.status->entry)&&(stat.status->entry->present_props))\r
320                                                                         //{\r
321                                                                         //      if (strstr(stat.status->entry->present_props, "svn:needs-lock"))\r
322                                                                         //              itemStates |= ITEMIS_NEEDSLOCK;\r
323                                                                         //}\r
324                                                                         //if ((stat.status->entry)&&(stat.status->entry->uuid))\r
325                                                                         //      uuidSource = CUnicodeUtils::StdGetUnicode(stat.status->entry->uuid);\r
326                                                                 }\r
327                                                                 else\r
328                                                                 {\r
329                                                                         // sometimes, git_client_status() returns with an error.\r
330                                                                         // in that case, we have to check if the working copy is versioned\r
331                                                                         // anyway to show the 'correct' context menu\r
332                                                                         if (askedpath.HasAdminDir())\r
333                                                                                 status = git_wc_status_normal;\r
334                                                                 }\r
335                                                         }\r
336                                                         catch ( ... )\r
337                                                         {\r
338                                                                 ATLTRACE2(_T("Exception in GitStatus::GetStatus()\n"));\r
339                                                         }\r
340 \r
341                                                         // TODO: should we really assume any sub-directory to be versioned\r
342                                                         //       or only if it contains versioned files\r
343                                                         if ( askedpath.IsDirectory() )\r
344                                                         {\r
345                                                                 if (askedpath.HasAdminDir())\r
346                                                                         itemStates |= ITEMIS_INSVN;\r
347                                                         }\r
348                                                         if ((status != git_wc_status_unversioned)&&(status != git_wc_status_ignored)&&(status != git_wc_status_none))\r
349                                                                 itemStates |= ITEMIS_INSVN;\r
350                                                         if (status == git_wc_status_ignored)\r
351                                                                 itemStates |= ITEMIS_IGNORED;\r
352                                                         if (status == git_wc_status_normal)\r
353                                                                 itemStates |= ITEMIS_NORMAL;\r
354                                                         if (status == git_wc_status_conflicted)\r
355                                                                 itemStates |= ITEMIS_CONFLICTED;\r
356                                                         if (status == git_wc_status_added)\r
357                                                                 itemStates |= ITEMIS_ADDED;\r
358                                                         if (status == git_wc_status_deleted)\r
359                                                                 itemStates |= ITEMIS_DELETED;\r
360                                                 }\r
361                                         }\r
362                                 } // for (int i = 0; i < count; i++)\r
363                                 GlobalUnlock ( drop );\r
364                                 ReleaseStgMedium ( &stg );\r
365 \r
366                         } // if (m_State == FileStateDropHandler) \r
367                         else\r
368                         {\r
369 \r
370                                 //Enumerate PIDLs which the user has selected\r
371                                 CIDA* cida = (CIDA*)GlobalLock(medium.hGlobal);\r
372                                 ItemIDList parent( GetPIDLFolder (cida));\r
373 \r
374                                 int count = cida->cidl;\r
375                                 BOOL statfetched = FALSE;\r
376                                 for (int i = 0; i < count; ++i)\r
377                                 {\r
378                                         ItemIDList child (GetPIDLItem (cida, i), &parent);\r
379                                         stdstring str = child.toString();\r
380                                         if ((str.empty() == false)&&(g_ShellCache.IsContextPathAllowed(str.c_str())))\r
381                                         {\r
382                                                 //check if our menu is requested for a subversion admin directory\r
383                                                 if (g_GitAdminDir.IsAdminDirPath(str.c_str()))\r
384                                                         continue;\r
385 \r
386                                                 files_.push_back(str);\r
387                                                 CTGitPath strpath;\r
388                                                 strpath.SetFromWin(str.c_str());\r
389                                                 itemStates |= (strpath.GetFileExtension().CompareNoCase(_T(".diff"))==0) ? ITEMIS_PATCHFILE : 0;\r
390                                                 itemStates |= (strpath.GetFileExtension().CompareNoCase(_T(".patch"))==0) ? ITEMIS_PATCHFILE : 0;\r
391                                                 if (!statfetched)\r
392                                                 {\r
393                                                         //get the Subversion status of the item\r
394                                                         git_wc_status_kind status = git_wc_status_none;\r
395                                                         if ((g_ShellCache.IsSimpleContext())&&(strpath.IsDirectory()))\r
396                                                         {\r
397                                                                 if (strpath.HasAdminDir())\r
398                                                                         status = git_wc_status_normal;\r
399                                                         }\r
400                                                         else\r
401                                                         {\r
402                                                                 try\r
403                                                                 {\r
404                                                                         GitStatus stat;\r
405                                                                         if (strpath.HasAdminDir())\r
406                                                                                 stat.GetStatus(strpath, false, true, true);\r
407                                                                         statuspath = str;\r
408                                                                         if (stat.status)\r
409                                                                         {\r
410                                                                                 status = GitStatus::GetMoreImportant(stat.status->text_status, stat.status->prop_status);\r
411                                                                                 fetchedstatus = status;\r
412                                                                                 //if ((stat.status->entry)&&(stat.status->entry->lock_token))\r
413                                                                                 //      itemStates |= (stat.status->entry->lock_token[0] != 0) ? ITEMIS_LOCKED : 0;\r
414                                                                                 if ( strpath.IsDirectory() )//if ((stat.status->entry)&&(stat.status->entry->kind == git_node_dir))\r
415                                                                                 {\r
416                                                                                         itemStates |= ITEMIS_FOLDER;\r
417                                                                                         if ((status != git_wc_status_unversioned)&&(status != git_wc_status_ignored)&&(status != git_wc_status_none))\r
418                                                                                                 itemStates |= ITEMIS_FOLDERINSVN;\r
419                                                                                 }\r
420                                                                                 // TODO: do we need to check that it's not a dir? does conflict options makes sense for dir in git?\r
421                                                                                 if (status == git_wc_status_conflicted)//if ((stat.status->entry)&&(stat.status->entry->conflict_wrk))\r
422                                                                                         itemStates |= ITEMIS_CONFLICTED;\r
423                                                                                 //if ((stat.status->entry)&&(stat.status->entry->present_props))\r
424                                                                                 //{\r
425                                                                                 //      if (strstr(stat.status->entry->present_props, "svn:needs-lock"))\r
426                                                                                 //              itemStates |= ITEMIS_NEEDSLOCK;\r
427                                                                                 //}\r
428                                                                                 //if ((stat.status->entry)&&(stat.status->entry->uuid))\r
429                                                                                 //      uuidSource = CUnicodeUtils::StdGetUnicode(stat.status->entry->uuid);\r
430                                                                         }       \r
431                                                                         else\r
432                                                                         {\r
433                                                                                 // sometimes, git_client_status() returns with an error.\r
434                                                                                 // in that case, we have to check if the working copy is versioned\r
435                                                                                 // anyway to show the 'correct' context menu\r
436                                                                                 if (strpath.HasAdminDir())\r
437                                                                                 {\r
438                                                                                         status = git_wc_status_normal;\r
439                                                                                         fetchedstatus = status;\r
440                                                                                 }\r
441                                                                         }\r
442                                                                         statfetched = TRUE;\r
443                                                                 }\r
444                                                                 catch ( ... )\r
445                                                                 {\r
446                                                                         ATLTRACE2(_T("Exception in GitStatus::GetStatus()\n"));\r
447                                                                 }\r
448                                                         }\r
449 \r
450                                                         // TODO: should we really assume any sub-directory to be versioned\r
451                                                         //       or only if it contains versioned files\r
452                                                         if ( strpath.IsDirectory() )\r
453                                                         {\r
454                                                                 if (strpath.HasAdminDir())\r
455                                                                         itemStates |= ITEMIS_INSVN;\r
456                                                         }\r
457                                                         if ((status != git_wc_status_unversioned)&&(status != git_wc_status_ignored)&&(status != git_wc_status_none))\r
458                                                                 itemStates |= ITEMIS_INSVN;\r
459                                                         if (status == git_wc_status_ignored)\r
460                                                         {\r
461                                                                 itemStates |= ITEMIS_IGNORED;\r
462                                                                 // the item is ignored. Get the svn:ignored properties so we can (maybe) later\r
463                                                                 // offer a 'remove from ignored list' entry\r
464 //                                                              GitProperties props(strpath.GetContainingDirectory(), false);\r
465 //                                                              ignoredprops.empty();\r
466 //                                                              for (int p=0; p<props.GetCount(); ++p)\r
467 //                                                              {\r
468 //                                                                      if (props.GetItemName(p).compare(stdstring(_T("svn:ignore")))==0)\r
469 //                                                                      {\r
470 //                                                                              std::string st = props.GetItemValue(p);\r
471 //                                                                              ignoredprops = MultibyteToWide(st.c_str());\r
472 //                                                                              // remove all escape chars ('\\')\r
473 //                                                                              std::remove(ignoredprops.begin(), ignoredprops.end(), '\\');\r
474 //                                                                              break;\r
475 //                                                                      }\r
476 //                                                              }\r
477                                                         }\r
478                                                         if (status == git_wc_status_normal)\r
479                                                                 itemStates |= ITEMIS_NORMAL;\r
480                                                         if (status == git_wc_status_conflicted)\r
481                                                                 itemStates |= ITEMIS_CONFLICTED;\r
482                                                         if (status == git_wc_status_added)\r
483                                                                 itemStates |= ITEMIS_ADDED;\r
484                                                         if (status == git_wc_status_deleted)\r
485                                                                 itemStates |= ITEMIS_DELETED;\r
486                                                 }\r
487                                         }\r
488                                 } // for (int i = 0; i < count; ++i)\r
489                                 ItemIDList child (GetPIDLItem (cida, 0), &parent);\r
490                                 if (g_ShellCache.HasSVNAdminDir(child.toString().c_str(), FALSE))\r
491                                         itemStates |= ITEMIS_INVERSIONEDFOLDER;\r
492                                 GlobalUnlock(medium.hGlobal);\r
493 \r
494                                 // if the item is a versioned folder, check if there's a patch file\r
495                                 // in the clipboard to be used in "Apply Patch"\r
496                                 UINT cFormatDiff = RegisterClipboardFormat(_T("TGIT_UNIFIEDDIFF"));\r
497                                 if (cFormatDiff)\r
498                                 {\r
499                                         if (IsClipboardFormatAvailable(cFormatDiff)) \r
500                                                 itemStates |= ITEMIS_PATCHINCLIPBOARD;\r
501                                 }\r
502                                 if (IsClipboardFormatAvailable(CF_HDROP)) \r
503                                         itemStates |= ITEMIS_PATHINCLIPBOARD;\r
504 \r
505                         }\r
506 \r
507                         ReleaseStgMedium ( &medium );\r
508                         if (medium.pUnkForRelease)\r
509                         {\r
510                                 IUnknown* relInterface = (IUnknown*)medium.pUnkForRelease;\r
511                                 relInterface->Release();\r
512                         }\r
513                 }\r
514         }\r
515 \r
516         // get folder background\r
517         if (pIDFolder)\r
518         {\r
519 \r
520                 ItemIDList list(pIDFolder);\r
521                 folder_ = list.toString();\r
522                 git_wc_status_kind status = git_wc_status_none;\r
523                 if (IsClipboardFormatAvailable(CF_HDROP)) \r
524                         itemStatesFolder |= ITEMIS_PATHINCLIPBOARD;\r
525                 \r
526                 CTGitPath askedpath;\r
527                 askedpath.SetFromWin(folder_.c_str());\r
528 \r
529                 if ((folder_.compare(statuspath)!=0)&&(g_ShellCache.IsContextPathAllowed(folder_.c_str())))\r
530                 {\r
531                         \r
532                         try\r
533                         {\r
534                                 GitStatus stat;\r
535                                 stat.GetStatus(CTGitPath(folder_.c_str()), false, true, true);\r
536                                 if (stat.status)\r
537                                 {\r
538                                         status = GitStatus::GetMoreImportant(stat.status->text_status, stat.status->prop_status);\r
539 //                                      if ((stat.status->entry)&&(stat.status->entry->lock_token))\r
540 //                                              itemStatesFolder |= (stat.status->entry->lock_token[0] != 0) ? ITEMIS_LOCKED : 0;\r
541 //                                      if ((stat.status->entry)&&(stat.status->entry->present_props))\r
542 //                                      {\r
543 //                                              if (strstr(stat.status->entry->present_props, "svn:needs-lock"))\r
544 //                                                      itemStatesFolder |= ITEMIS_NEEDSLOCK;\r
545 //                                      }\r
546 //                                      if ((stat.status->entry)&&(stat.status->entry->uuid))\r
547 //                                              uuidTarget = CUnicodeUtils::StdGetUnicode(stat.status->entry->uuid);\r
548                                 \r
549                                 }\r
550                                 else\r
551                                 {\r
552                                         // sometimes, git_client_status() returns with an error.\r
553                                         // in that case, we have to check if the working copy is versioned\r
554                                         // anyway to show the 'correct' context menu\r
555                                         if (askedpath.HasAdminDir())\r
556                                                 status = git_wc_status_normal;\r
557                                 }\r
558                                 \r
559                                 //if ((status != git_wc_status_unversioned)&&(status != git_wc_status_ignored)&&(status != git_wc_status_none))\r
560                                 if (askedpath.HasAdminDir())\r
561                                         itemStatesFolder |= ITEMIS_INSVN;\r
562                                 if (status == git_wc_status_normal)\r
563                                         itemStatesFolder |= ITEMIS_NORMAL;\r
564                                 if (status == git_wc_status_conflicted)\r
565                                         itemStatesFolder |= ITEMIS_CONFLICTED;\r
566                                 if (status == git_wc_status_added)\r
567                                         itemStatesFolder |= ITEMIS_ADDED;\r
568                                 if (status == git_wc_status_deleted)\r
569                                         itemStatesFolder |= ITEMIS_DELETED;\r
570 \r
571                         }\r
572                         catch ( ... )\r
573                         {\r
574                                 ATLTRACE2(_T("Exception in GitStatus::GetStatus()\n"));\r
575                         }\r
576                 }\r
577                 else\r
578                 {\r
579                         status = fetchedstatus;\r
580                 }\r
581                 //if ((status != git_wc_status_unversioned)&&(status != git_wc_status_ignored)&&(status != git_wc_status_none))\r
582                 if (askedpath.HasAdminDir())\r
583                 {\r
584                         itemStatesFolder |= ITEMIS_FOLDERINSVN;\r
585                 }\r
586                 if (status == git_wc_status_ignored)\r
587                         itemStatesFolder |= ITEMIS_IGNORED;\r
588                 itemStatesFolder |= ITEMIS_FOLDER;\r
589                 if (files_.size() == 0)\r
590                         itemStates |= ITEMIS_ONLYONE;\r
591                 if (m_State != FileStateDropHandler)\r
592                         itemStates |= itemStatesFolder;\r
593 \r
594         }\r
595         if (files_.size() == 2)\r
596                 itemStates |= ITEMIS_TWO;\r
597         if ((files_.size() == 1)&&(g_ShellCache.IsContextPathAllowed(files_.front().c_str())))\r
598         {\r
599 \r
600                 itemStates |= ITEMIS_ONLYONE;\r
601                 if (m_State != FileStateDropHandler)\r
602                 {\r
603                         if (PathIsDirectory(files_.front().c_str()))\r
604                         {\r
605                                 folder_ = files_.front();\r
606                                 git_wc_status_kind status = git_wc_status_none;\r
607                                 CTGitPath askedpath;\r
608                                 askedpath.SetFromWin(folder_.c_str());\r
609 \r
610                                 if (folder_.compare(statuspath)!=0)\r
611                                 {                               \r
612                                         try\r
613                                         {\r
614                                                 GitStatus stat;\r
615                                                 stat.GetStatus(CTGitPath(folder_.c_str()), false, true, true);\r
616                                                 if (stat.status)\r
617                                                 {\r
618                                                         status = GitStatus::GetMoreImportant(stat.status->text_status, stat.status->prop_status);\r
619 //                                                      if ((stat.status->entry)&&(stat.status->entry->lock_token))\r
620 //                                                              itemStates |= (stat.status->entry->lock_token[0] != 0) ? ITEMIS_LOCKED : 0;\r
621 //                                                      if ((stat.status->entry)&&(stat.status->entry->present_props))\r
622 //                                                      {\r
623 //                                                              if (strstr(stat.status->entry->present_props, "svn:needs-lock"))\r
624 //                                                                      itemStates |= ITEMIS_NEEDSLOCK;\r
625 //                                                      }\r
626 //                                                      if ((stat.status->entry)&&(stat.status->entry->uuid))\r
627 //                                                              uuidTarget = CUnicodeUtils::StdGetUnicode(stat.status->entry->uuid);\r
628                                                 }\r
629                                         }\r
630                                         catch ( ... )\r
631                                         {\r
632                                                 ATLTRACE2(_T("Exception in GitStatus::GetStatus()\n"));\r
633                                         }\r
634                                 }\r
635                                 else\r
636                                 {\r
637                                         status = fetchedstatus;\r
638                                 }\r
639                                 //if ((status != git_wc_status_unversioned)&&(status != git_wc_status_ignored)&&(status != git_wc_status_none))\r
640                                 if (askedpath.HasAdminDir())\r
641                                         itemStates |= ITEMIS_FOLDERINSVN;\r
642                                 if (status == git_wc_status_ignored)\r
643                                         itemStates |= ITEMIS_IGNORED;\r
644                                 itemStates |= ITEMIS_FOLDER;\r
645                                 if (status == git_wc_status_added)\r
646                                         itemStates |= ITEMIS_ADDED;\r
647                                 if (status == git_wc_status_deleted)\r
648                                         itemStates |= ITEMIS_DELETED;\r
649                         }\r
650                 }\r
651         \r
652         }\r
653         \r
654         return NOERROR;\r
655 }\r
656 \r
657 void CShellExt::InsertGitMenu(BOOL istop, HMENU menu, UINT pos, UINT_PTR id, UINT stringid, UINT icon, UINT idCmdFirst, GitCommands com, UINT uFlags)\r
658 {\r
659         TCHAR menutextbuffer[255] = {0};\r
660         TCHAR verbsbuffer[255] = {0};\r
661         MAKESTRING(stringid);\r
662 \r
663         if (istop)\r
664         {\r
665                 //menu entry for the top context menu, so append an "Git " before\r
666                 //the menu text to indicate where the entry comes from\r
667                 _tcscpy_s(menutextbuffer, 255, _T("Git "));\r
668         }\r
669         _tcscat_s(menutextbuffer, 255, stringtablebuffer);\r
670         if ((fullver < 0x500)||(fullver == 0x500 && !uFlags))\r
671         {\r
672                 InsertMenu(menu, pos, MF_BYPOSITION | MF_STRING , id, menutextbuffer);\r
673                 if (fullver >= 0x500)\r
674                 {\r
675                         // on win2k, the context menu does not work properly if we use\r
676                         // icon bitmaps. At least the menu text is empty in the context menu\r
677                         // for folder backgrounds (seems like a win2k bug).\r
678                         HBITMAP bmp = IconToBitmap(icon); \r
679                         SetMenuItemBitmaps(menu, pos, MF_BYPOSITION, bmp, bmp);\r
680                 }\r
681         }\r
682         else\r
683         {\r
684                 MENUITEMINFO menuiteminfo = {0};\r
685                 menuiteminfo.cbSize = sizeof(menuiteminfo);\r
686                 menuiteminfo.fMask = MIIM_FTYPE | MIIM_ID | MIIM_BITMAP | MIIM_STRING;\r
687                 menuiteminfo.fType = MFT_STRING;\r
688                 menuiteminfo.dwTypeData = menutextbuffer;\r
689                 if (icon)\r
690                         menuiteminfo.hbmpItem = (fullver >= 0x600) ? IconToBitmapPARGB32(icon) : HBMMENU_CALLBACK;\r
691                 menuiteminfo.wID = id;\r
692                 InsertMenuItem(menu, pos, TRUE, &menuiteminfo);\r
693         }\r
694 \r
695         if (istop)\r
696         {\r
697                 //menu entry for the top context menu, so append an "Git " before\r
698                 //the menu text to indicate where the entry comes from\r
699                 _tcscpy_s(menutextbuffer, 255, _T("Git "));\r
700         }\r
701         LoadString(g_hResInst, stringid, verbsbuffer, sizeof(verbsbuffer));\r
702         _tcscat_s(menutextbuffer, 255, verbsbuffer);\r
703         stdstring verb = stdstring(menutextbuffer);\r
704         if (verb.find('&') != -1)\r
705         {\r
706                 verb.erase(verb.find('&'),1);\r
707         }\r
708         myVerbsMap[verb] = id - idCmdFirst;\r
709         myVerbsMap[verb] = id;\r
710         myVerbsIDMap[id - idCmdFirst] = verb;\r
711         myVerbsIDMap[id] = verb;\r
712         // We store the relative and absolute diameter\r
713         // (drawitem callback uses absolute, others relative)\r
714         myIDMap[id - idCmdFirst] = com;\r
715         myIDMap[id] = com;\r
716         if (!istop)\r
717                 mySubMenuMap[pos] = com;\r
718 }\r
719 \r
720 HBITMAP CShellExt::IconToBitmap(UINT uIcon)\r
721 {\r
722         std::map<UINT, HBITMAP>::iterator bitmap_it = bitmaps.lower_bound(uIcon);\r
723         if (bitmap_it != bitmaps.end() && bitmap_it->first == uIcon)\r
724                 return bitmap_it->second;\r
725 \r
726         HICON hIcon = (HICON)LoadImage(g_hResInst, MAKEINTRESOURCE(uIcon), IMAGE_ICON, 12, 12, LR_DEFAULTCOLOR);\r
727         if (!hIcon)\r
728                 return NULL;\r
729 \r
730         RECT rect;\r
731 \r
732         rect.right = ::GetSystemMetrics(SM_CXMENUCHECK);\r
733         rect.bottom = ::GetSystemMetrics(SM_CYMENUCHECK);\r
734 \r
735         rect.left = rect.top = 0;\r
736 \r
737         HWND desktop = ::GetDesktopWindow();\r
738         if (desktop == NULL)\r
739         {\r
740                 DestroyIcon(hIcon);\r
741                 return NULL;\r
742         }\r
743 \r
744         HDC screen_dev = ::GetDC(desktop);\r
745         if (screen_dev == NULL)\r
746         {\r
747                 DestroyIcon(hIcon);\r
748                 return NULL;\r
749         }\r
750 \r
751         // Create a compatible DC\r
752         HDC dst_hdc = ::CreateCompatibleDC(screen_dev);\r
753         if (dst_hdc == NULL)\r
754         {\r
755                 DestroyIcon(hIcon);\r
756                 ::ReleaseDC(desktop, screen_dev); \r
757                 return NULL;\r
758         }\r
759 \r
760         // Create a new bitmap of icon size\r
761         HBITMAP bmp = ::CreateCompatibleBitmap(screen_dev, rect.right, rect.bottom);\r
762         if (bmp == NULL)\r
763         {\r
764                 DestroyIcon(hIcon);\r
765                 ::DeleteDC(dst_hdc);\r
766                 ::ReleaseDC(desktop, screen_dev); \r
767                 return NULL;\r
768         }\r
769 \r
770         // Select it into the compatible DC\r
771         HBITMAP old_dst_bmp = (HBITMAP)::SelectObject(dst_hdc, bmp);\r
772         if (old_dst_bmp == NULL)\r
773         {\r
774                 DestroyIcon(hIcon);\r
775                 return NULL;\r
776         }\r
777 \r
778         // Fill the background of the compatible DC with the white color\r
779         // that is taken by menu routines as transparent\r
780         ::SetBkColor(dst_hdc, RGB(255, 255, 255));\r
781         ::ExtTextOut(dst_hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);\r
782 \r
783         // Draw the icon into the compatible DC\r
784         ::DrawIconEx(dst_hdc, 0, 0, hIcon, rect.right, rect.bottom, 0, NULL, DI_NORMAL);\r
785 \r
786         // Restore settings\r
787         ::SelectObject(dst_hdc, old_dst_bmp);\r
788         ::DeleteDC(dst_hdc);\r
789         ::ReleaseDC(desktop, screen_dev); \r
790         DestroyIcon(hIcon);\r
791         if (bmp)\r
792                 bitmaps.insert(bitmap_it, std::make_pair(uIcon, bmp));\r
793         return bmp;\r
794 }\r
795 \r
796 bool CShellExt::WriteClipboardPathsToTempFile(stdstring& tempfile)\r
797 {\r
798         bool bRet = true;\r
799         tempfile = stdstring();\r
800         //write all selected files and paths to a temporary file\r
801         //for TortoiseProc.exe to read out again.\r
802         DWORD written = 0;\r
803         DWORD pathlength = GetTempPath(0, NULL);\r
804         TCHAR * path = new TCHAR[pathlength+1];\r
805         TCHAR * tempFile = new TCHAR[pathlength + 100];\r
806         GetTempPath (pathlength+1, path);\r
807         GetTempFileName (path, _T("git"), 0, tempFile);\r
808         tempfile = stdstring(tempFile);\r
809 \r
810         HANDLE file = ::CreateFile (tempFile,\r
811                 GENERIC_WRITE, \r
812                 FILE_SHARE_READ, \r
813                 0, \r
814                 CREATE_ALWAYS, \r
815                 FILE_ATTRIBUTE_TEMPORARY,\r
816                 0);\r
817 \r
818         delete [] path;\r
819         delete [] tempFile;\r
820         if (file == INVALID_HANDLE_VALUE)\r
821                 return false;\r
822 \r
823         if (!IsClipboardFormatAvailable(CF_HDROP))\r
824                 return false;\r
825         if (!OpenClipboard(NULL))\r
826                 return false;\r
827 \r
828         stdstring sClipboardText;\r
829         HGLOBAL hglb = GetClipboardData(CF_HDROP);\r
830         HDROP hDrop = (HDROP)GlobalLock(hglb);\r
831         if(hDrop != NULL)\r
832         {\r
833                 TCHAR szFileName[MAX_PATH];\r
834                 UINT cFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); \r
835                 for(UINT i = 0; i < cFiles; ++i)\r
836                 {\r
837                         DragQueryFile(hDrop, i, szFileName, sizeof(szFileName));\r
838                         stdstring filename = szFileName;\r
839                         ::WriteFile (file, filename.c_str(), filename.size()*sizeof(TCHAR), &written, 0);\r
840                         ::WriteFile (file, _T("\n"), 2, &written, 0);\r
841                 }\r
842                 GlobalUnlock(hDrop);\r
843         }\r
844         else bRet = false;\r
845         GlobalUnlock(hglb);\r
846 \r
847         CloseClipboard();\r
848         ::CloseHandle(file);\r
849 \r
850         return bRet;\r
851 }\r
852 \r
853 stdstring CShellExt::WriteFileListToTempFile()\r
854 {\r
855         //write all selected files and paths to a temporary file\r
856         //for TortoiseProc.exe to read out again.\r
857         DWORD pathlength = GetTempPath(0, NULL);\r
858         TCHAR * path = new TCHAR[pathlength+1];\r
859         TCHAR * tempFile = new TCHAR[pathlength + 100];\r
860         GetTempPath (pathlength+1, path);\r
861         GetTempFileName (path, _T("git"), 0, tempFile);\r
862         stdstring retFilePath = stdstring(tempFile);\r
863         \r
864         HANDLE file = ::CreateFile (tempFile,\r
865                                                                 GENERIC_WRITE, \r
866                                                                 FILE_SHARE_READ, \r
867                                                                 0, \r
868                                                                 CREATE_ALWAYS, \r
869                                                                 FILE_ATTRIBUTE_TEMPORARY,\r
870                                                                 0);\r
871 \r
872         delete [] path;\r
873         delete [] tempFile;\r
874         if (file == INVALID_HANDLE_VALUE)\r
875                 return stdstring();\r
876                 \r
877         DWORD written = 0;\r
878         if (files_.empty())\r
879         {\r
880                 ::WriteFile (file, folder_.c_str(), folder_.size()*sizeof(TCHAR), &written, 0);\r
881                 ::WriteFile (file, _T("\n"), 2, &written, 0);\r
882         }\r
883 \r
884         for (std::vector<stdstring>::iterator I = files_.begin(); I != files_.end(); ++I)\r
885         {\r
886                 ::WriteFile (file, I->c_str(), I->size()*sizeof(TCHAR), &written, 0);\r
887                 ::WriteFile (file, _T("\n"), 2, &written, 0);\r
888         }\r
889         ::CloseHandle(file);\r
890         return retFilePath;\r
891 }\r
892 \r
893 STDMETHODIMP CShellExt::QueryDropContext(UINT uFlags, UINT idCmdFirst, HMENU hMenu, UINT &indexMenu)\r
894 {\r
895         PreserveChdir preserveChdir;\r
896         LoadLangDll();\r
897 \r
898         if ((uFlags & CMF_DEFAULTONLY)!=0)\r
899                 return NOERROR;                                 //we don't change the default action\r
900 \r
901         if ((files_.size() == 0)||(folder_.size() == 0))\r
902                 return NOERROR;\r
903 \r
904         if (((uFlags & 0x000f)!=CMF_NORMAL)&&(!(uFlags & CMF_EXPLORE))&&(!(uFlags & CMF_VERBSONLY)))\r
905                 return NOERROR;\r
906 \r
907         bool bSourceAndTargetFromSameRepository = (uuidSource.compare(uuidTarget) == 0) || uuidSource.empty() || uuidTarget.empty();\r
908 \r
909         //the drop handler only has eight commands, but not all are visible at the same time:\r
910         //if the source file(s) are under version control then those files can be moved\r
911         //to the new location or they can be moved with a rename, \r
912         //if they are unversioned then they can be added to the working copy\r
913         //if they are versioned, they also can be exported to an unversioned location\r
914         UINT idCmd = idCmdFirst;\r
915 \r
916         // Git move here\r
917         // available if source is versioned but not added, target is versioned, source and target from same repository or target folder is added\r
918         if ((bSourceAndTargetFromSameRepository||(itemStatesFolder & ITEMIS_ADDED))&&(itemStatesFolder & ITEMIS_FOLDERINSVN)&&((itemStates & ITEMIS_INSVN)&&((~itemStates) & ITEMIS_ADDED)))\r
919                 InsertGitMenu(FALSE, hMenu, indexMenu++, idCmd++, IDS_DROPMOVEMENU, 0, idCmdFirst, ShellMenuDropMove, uFlags);\r
920 \r
921         // Git move and rename here\r
922         // available if source is a single, versioned but not added item, target is versioned, source and target from same repository or target folder is added\r
923         if ((bSourceAndTargetFromSameRepository||(itemStatesFolder & ITEMIS_ADDED))&&(itemStatesFolder & ITEMIS_FOLDERINSVN)&&(itemStates & ITEMIS_INSVN)&&(itemStates & ITEMIS_ONLYONE)&&((~itemStates) & ITEMIS_ADDED))\r
924                 InsertGitMenu(FALSE, hMenu, indexMenu++, idCmd++, IDS_DROPMOVERENAMEMENU, 0, idCmdFirst, ShellMenuDropMoveRename, uFlags);\r
925 \r
926         // Git copy here\r
927         // available if source is versioned but not added, target is versioned, source and target from same repository or target folder is added\r
928         if ((bSourceAndTargetFromSameRepository||(itemStatesFolder & ITEMIS_ADDED))&&(itemStatesFolder & ITEMIS_FOLDERINSVN)&&(itemStates & ITEMIS_INSVN)&&((~itemStates) & ITEMIS_ADDED))\r
929                 InsertGitMenu(FALSE, hMenu, indexMenu++, idCmd++, IDS_DROPCOPYMENU, 0, idCmdFirst, ShellMenuDropCopy, uFlags);\r
930 \r
931         // Git copy and rename here, source and target from same repository\r
932         // available if source is a single, versioned but not added item, target is versioned or target folder is added\r
933         if ((bSourceAndTargetFromSameRepository||(itemStatesFolder & ITEMIS_ADDED))&&(itemStatesFolder & ITEMIS_FOLDERINSVN)&&(itemStates & ITEMIS_INSVN)&&(itemStates & ITEMIS_ONLYONE)&&((~itemStates) & ITEMIS_ADDED))\r
934                 InsertGitMenu(FALSE, hMenu, indexMenu++, idCmd++, IDS_DROPCOPYRENAMEMENU, 0, idCmdFirst, ShellMenuDropCopyRename, uFlags);\r
935 \r
936         // Git add here\r
937         // available if target is versioned and source is either unversioned or from another repository\r
938         if ((itemStatesFolder & ITEMIS_FOLDERINSVN)&&(((~itemStates) & ITEMIS_INSVN)||!bSourceAndTargetFromSameRepository))\r
939                 InsertGitMenu(FALSE, hMenu, indexMenu++, idCmd++, IDS_DROPCOPYADDMENU, 0, idCmdFirst, ShellMenuDropCopyAdd, uFlags);\r
940 \r
941         // Git export here\r
942         // available if source is versioned and a folder\r
943         if ((itemStates & ITEMIS_INSVN)&&(itemStates & ITEMIS_FOLDER))\r
944                 InsertGitMenu(FALSE, hMenu, indexMenu++, idCmd++, IDS_DROPEXPORTMENU, 0, idCmdFirst, ShellMenuDropExport, uFlags);\r
945 \r
946         // Git export all here\r
947         // available if source is versioned and a folder\r
948         if ((itemStates & ITEMIS_INSVN)&&(itemStates & ITEMIS_FOLDER))\r
949                 InsertGitMenu(FALSE, hMenu, indexMenu++, idCmd++, IDS_DROPEXPORTEXTENDEDMENU, 0, idCmdFirst, ShellMenuDropExportExtended, uFlags);\r
950 \r
951         // apply patch\r
952         // available if source is a patchfile\r
953         if (itemStates & ITEMIS_PATCHFILE)\r
954                 InsertGitMenu(FALSE, hMenu, indexMenu++, idCmd++, IDS_MENUAPPLYPATCH, 0, idCmdFirst, ShellMenuApplyPatch, uFlags);\r
955 \r
956         // separator\r
957         if (idCmd != idCmdFirst)\r
958                 InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL); \r
959 \r
960         return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, 0, (USHORT)(idCmd - idCmdFirst)));\r
961 }\r
962 \r
963 STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,\r
964                                          UINT indexMenu,\r
965                                          UINT idCmdFirst,\r
966                                          UINT /*idCmdLast*/,\r
967                                          UINT uFlags)\r
968 {\r
969         ATLTRACE("Shell :: QueryContextMenu\n");\r
970         PreserveChdir preserveChdir;\r
971         \r
972         //first check if our drop handler is called\r
973         //and then (if true) provide the context menu for the\r
974         //drop handler\r
975         if (m_State == FileStateDropHandler)\r
976         {\r
977                 return QueryDropContext(uFlags, idCmdFirst, hMenu, indexMenu);\r
978         }\r
979 \r
980         if ((uFlags & CMF_DEFAULTONLY)!=0)\r
981                 return NOERROR;                                 //we don't change the default action\r
982 \r
983         if ((files_.size() == 0)&&(folder_.size() == 0))\r
984                 return NOERROR;\r
985 \r
986         if (((uFlags & 0x000f)!=CMF_NORMAL)&&(!(uFlags & CMF_EXPLORE))&&(!(uFlags & CMF_VERBSONLY)))\r
987                 return NOERROR;\r
988 \r
989         int csidlarray[] = \r
990         {\r
991                 CSIDL_BITBUCKET,\r
992                 CSIDL_CDBURN_AREA,\r
993                 CSIDL_COMMON_FAVORITES,\r
994                 CSIDL_COMMON_STARTMENU,\r
995                 CSIDL_COMPUTERSNEARME,\r
996                 CSIDL_CONNECTIONS,\r
997                 CSIDL_CONTROLS,\r
998                 CSIDL_COOKIES,\r
999                 CSIDL_FAVORITES,\r
1000                 CSIDL_FONTS,\r
1001                 CSIDL_HISTORY,\r
1002                 CSIDL_INTERNET,\r
1003                 CSIDL_INTERNET_CACHE,\r
1004                 CSIDL_NETHOOD,\r
1005                 CSIDL_NETWORK,\r
1006                 CSIDL_PRINTERS,\r
1007                 CSIDL_PRINTHOOD,\r
1008                 CSIDL_RECENT,\r
1009                 CSIDL_SENDTO,\r
1010                 CSIDL_STARTMENU,\r
1011                 0\r
1012         };\r
1013         if (IsIllegalFolder(folder_, csidlarray))\r
1014                 return NOERROR;\r
1015 \r
1016         if (folder_.empty())\r
1017         {\r
1018                 // folder is empty, but maybe files are selected\r
1019                 if (files_.size() == 0)\r
1020                         return NOERROR; // nothing selected - we don't have a menu to show\r
1021                 // check whether a selected entry is an UID - those are namespace extensions\r
1022                 // which we can't handle\r
1023                 for (std::vector<stdstring>::const_iterator it = files_.begin(); it != files_.end(); ++it)\r
1024                 {\r
1025                         if (_tcsncmp(it->c_str(), _T("::{"), 3)==0)\r
1026                                 return NOERROR;\r
1027                 }\r
1028         }\r
1029 \r
1030         //check if our menu is requested for a subversion admin directory\r
1031         if (g_GitAdminDir.IsAdminDirPath(folder_.c_str()))\r
1032                 return NOERROR;\r
1033 \r
1034         if (uFlags & CMF_EXTENDEDVERBS)\r
1035                 itemStates |= ITEMIS_EXTENDED;\r
1036 \r
1037         const BOOL bShortcut = !!(uFlags & CMF_VERBSONLY);\r
1038         if ( bShortcut && (files_.size()==1))\r
1039         {\r
1040                 // Don't show the context menu for a link if the\r
1041                 // destination is not part of a working copy.\r
1042                 // It would only show the standard menu items\r
1043                 // which are already shown for the lnk-file.\r
1044                 CString path = files_.front().c_str();\r
1045                 if ( !g_GitAdminDir.HasAdminDir(path) )\r
1046                 {\r
1047                         return NOERROR;\r
1048                 }\r
1049         }\r
1050 \r
1051         //check if we already added our menu entry for a folder.\r
1052         //we check that by iterating through all menu entries and check if \r
1053         //the dwItemData member points to our global ID string. That string is set\r
1054         //by our shell extension when the folder menu is inserted.\r
1055         TCHAR menubuf[MAX_PATH];\r
1056         int count = GetMenuItemCount(hMenu);\r
1057         for (int i=0; i<count; ++i)\r
1058         {\r
1059                 MENUITEMINFO miif;\r
1060                 SecureZeroMemory(&miif, sizeof(MENUITEMINFO));\r
1061                 miif.cbSize = sizeof(MENUITEMINFO);\r
1062                 miif.fMask = MIIM_DATA;\r
1063                 miif.dwTypeData = menubuf;\r
1064                 miif.cch = sizeof(menubuf)/sizeof(TCHAR);\r
1065                 GetMenuItemInfo(hMenu, i, TRUE, &miif);\r
1066                 if (miif.dwItemData == (ULONG_PTR)g_MenuIDString)\r
1067                         return NOERROR;\r
1068         }\r
1069 \r
1070         LoadLangDll();\r
1071         UINT idCmd = idCmdFirst;\r
1072 \r
1073         //create the sub menu\r
1074         HMENU subMenu = CreateMenu();\r
1075         int indexSubMenu = 0;\r
1076 \r
1077         unsigned __int64 topmenu = g_ShellCache.GetMenuLayout();\r
1078         unsigned __int64 menumask = g_ShellCache.GetMenuMask();\r
1079 \r
1080         int menuIndex = 0;\r
1081         bool bAddSeparator = false;\r
1082         bool bMenuEntryAdded = false;\r
1083         bool bMenuEmpty = true;\r
1084         // insert separator at start\r
1085         InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL); idCmd++;\r
1086         bool bShowIcons = !!DWORD(CRegStdWORD(_T("Software\\TortoiseGit\\ShowContextMenuIcons"), TRUE));\r
1087         // ?? TortoiseSVN had this as (fullver <= 0x0500) this disabled icons in win2k, but icons work fine in win2k\r
1088         if (fullver < 0x0500)\r
1089                 bShowIcons = false;\r
1090         while (menuInfo[menuIndex].command != ShellMenuLastEntry)\r
1091         {\r
1092                 if (menuInfo[menuIndex].command == ShellSeparator)\r
1093                 {\r
1094                         // we don't add a separator immediately. Because there might not be\r
1095                         // another 'normal' menu entry after we insert a separator.\r
1096                         // we simply set a flag here, indicating that before the next\r
1097                         // 'normal' menu entry, a separator should be added.\r
1098                         if (!bMenuEmpty)\r
1099                                 bAddSeparator = true;\r
1100                 }\r
1101                 else\r
1102                 {\r
1103                         // check the conditions whether to show the menu entry or not\r
1104                         bool bInsertMenu = false;\r
1105 \r
1106                         if (menuInfo[menuIndex].firstyes && menuInfo[menuIndex].firstno)\r
1107                         {\r
1108                                 if (((menuInfo[menuIndex].firstyes & itemStates) == menuInfo[menuIndex].firstyes)\r
1109                                         &&\r
1110                                         ((menuInfo[menuIndex].firstno & (~itemStates)) == menuInfo[menuIndex].firstno))\r
1111                                         bInsertMenu = true;\r
1112                         }\r
1113                         else if ((menuInfo[menuIndex].firstyes)&&((menuInfo[menuIndex].firstyes & itemStates) == menuInfo[menuIndex].firstyes))\r
1114                                 bInsertMenu = true;\r
1115                         else if ((menuInfo[menuIndex].firstno)&&((menuInfo[menuIndex].firstno & (~itemStates)) == menuInfo[menuIndex].firstno))\r
1116                                 bInsertMenu = true;\r
1117 \r
1118                         if (menuInfo[menuIndex].secondyes && menuInfo[menuIndex].secondno)\r
1119                         {\r
1120                                 if (((menuInfo[menuIndex].secondyes & itemStates) == menuInfo[menuIndex].secondyes)\r
1121                                         &&\r
1122                                         ((menuInfo[menuIndex].secondno & (~itemStates)) == menuInfo[menuIndex].secondno))\r
1123                                         bInsertMenu = true;\r
1124                         }\r
1125                         else if ((menuInfo[menuIndex].secondyes)&&((menuInfo[menuIndex].secondyes & itemStates) == menuInfo[menuIndex].secondyes))\r
1126                                 bInsertMenu = true;\r
1127                         else if ((menuInfo[menuIndex].secondno)&&((menuInfo[menuIndex].secondno & (~itemStates)) == menuInfo[menuIndex].secondno))\r
1128                                 bInsertMenu = true;\r
1129 \r
1130                         if (menuInfo[menuIndex].thirdyes && menuInfo[menuIndex].thirdno)\r
1131                         {\r
1132                                 if (((menuInfo[menuIndex].thirdyes & itemStates) == menuInfo[menuIndex].thirdyes)\r
1133                                         &&\r
1134                                         ((menuInfo[menuIndex].thirdno & (~itemStates)) == menuInfo[menuIndex].thirdno))\r
1135                                         bInsertMenu = true;\r
1136                         }\r
1137                         else if ((menuInfo[menuIndex].thirdyes)&&((menuInfo[menuIndex].thirdyes & itemStates) == menuInfo[menuIndex].thirdyes))\r
1138                                 bInsertMenu = true;\r
1139                         else if ((menuInfo[menuIndex].thirdno)&&((menuInfo[menuIndex].thirdno & (~itemStates)) == menuInfo[menuIndex].thirdno))\r
1140                                 bInsertMenu = true;\r
1141 \r
1142                         if (menuInfo[menuIndex].fourthyes && menuInfo[menuIndex].fourthno)\r
1143                         {\r
1144                                 if (((menuInfo[menuIndex].fourthyes & itemStates) == menuInfo[menuIndex].fourthyes)\r
1145                                         &&\r
1146                                         ((menuInfo[menuIndex].fourthno & (~itemStates)) == menuInfo[menuIndex].fourthno))\r
1147                                         bInsertMenu = true;\r
1148                         }\r
1149                         else if ((menuInfo[menuIndex].fourthyes)&&((menuInfo[menuIndex].fourthyes & itemStates) == menuInfo[menuIndex].fourthyes))\r
1150                                 bInsertMenu = true;\r
1151                         else if ((menuInfo[menuIndex].fourthno)&&((menuInfo[menuIndex].fourthno & (~itemStates)) == menuInfo[menuIndex].fourthno))\r
1152                                 bInsertMenu = true;\r
1153 \r
1154                         if (menuInfo[menuIndex].menuID & (~menumask))\r
1155                         {\r
1156                                 if (bInsertMenu)\r
1157                                 {\r
1158                                         // insert a separator\r
1159                                         if ((bMenuEntryAdded)&&(bAddSeparator))\r
1160                                         {\r
1161                                                 bAddSeparator = false;\r
1162                                                 bMenuEntryAdded = false;\r
1163                                                 InsertMenu(subMenu, indexSubMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL); \r
1164                                                 idCmd++;\r
1165                                         }\r
1166                                         \r
1167                                         // handle special cases (sub menus)\r
1168                                         if ((menuInfo[menuIndex].command == ShellMenuIgnoreSub)||(menuInfo[menuIndex].command == ShellMenuUnIgnoreSub))\r
1169                                         {\r
1170                                                 InsertIgnoreSubmenus(idCmd, idCmdFirst, hMenu, subMenu, indexMenu, indexSubMenu, topmenu, bShowIcons);\r
1171                                                 bMenuEntryAdded = true;\r
1172                                                 bMenuEmpty = false;\r
1173                                         }\r
1174                                         else\r
1175                                         {\r
1176                                                 bool bIsTop = ((topmenu & menuInfo[menuIndex].menuID) != 0);\r
1177 \r
1178                                                 // insert the menu entry\r
1179                                                 InsertGitMenu(  bIsTop,\r
1180                                                                                 bIsTop ? hMenu : subMenu,\r
1181                                                                                 bIsTop ? indexMenu++ : indexSubMenu++,\r
1182                                                                                 idCmd++,\r
1183                                                                                 menuInfo[menuIndex].menuTextID,\r
1184                                                                                 bShowIcons ? menuInfo[menuIndex].iconID : 0,\r
1185                                                                                 idCmdFirst,\r
1186                                                                                 menuInfo[menuIndex].command,\r
1187                                                                                 uFlags);\r
1188                                                 if (!bIsTop)\r
1189                                                 {\r
1190                                                         bMenuEntryAdded = true;\r
1191                                                         bMenuEmpty = false;\r
1192                                                 }\r
1193                                         }\r
1194                                 }\r
1195                         }\r
1196                 }\r
1197                 menuIndex++;\r
1198         }\r
1199 \r
1200         //add sub menu to main context menu\r
1201         //don't use InsertMenu because this will lead to multiple menu entries in the explorer file menu.\r
1202         //see http://support.microsoft.com/default.aspx?scid=kb;en-us;214477 for details of that.\r
1203         MAKESTRING(IDS_MENUSUBMENU);\r
1204         MENUITEMINFO menuiteminfo;\r
1205         SecureZeroMemory(&menuiteminfo, sizeof(menuiteminfo));\r
1206         menuiteminfo.cbSize = sizeof(menuiteminfo);\r
1207         menuiteminfo.fType = MFT_STRING;\r
1208         menuiteminfo.dwTypeData = stringtablebuffer;\r
1209 \r
1210         UINT uIcon = bShowIcons ? IDI_APP : 0;\r
1211         if (folder_.size())\r
1212         {\r
1213                 uIcon = bShowIcons ? IDI_MENUFOLDER : 0;\r
1214                 myIDMap[idCmd - idCmdFirst] = ShellSubMenuFolder;\r
1215                 myIDMap[idCmd] = ShellSubMenuFolder;\r
1216                 menuiteminfo.dwItemData = (ULONG_PTR)g_MenuIDString;\r
1217         }\r
1218         else if (!bShortcut && (files_.size()==1))\r
1219         {\r
1220                 uIcon = bShowIcons ? IDI_MENUFILE : 0;\r
1221                 myIDMap[idCmd - idCmdFirst] = ShellSubMenuFile;\r
1222                 myIDMap[idCmd] = ShellSubMenuFile;\r
1223         }\r
1224         else if (bShortcut && (files_.size()==1))\r
1225         {\r
1226                 uIcon = bShowIcons ? IDI_MENULINK : 0;\r
1227                 myIDMap[idCmd - idCmdFirst] = ShellSubMenuLink;\r
1228                 myIDMap[idCmd] = ShellSubMenuLink;\r
1229         }\r
1230         else if (files_.size() > 1)\r
1231         {\r
1232                 uIcon = bShowIcons ? IDI_MENUMULTIPLE : 0;\r
1233                 myIDMap[idCmd - idCmdFirst] = ShellSubMenuMultiple;\r
1234                 myIDMap[idCmd] = ShellSubMenuMultiple;\r
1235         }\r
1236         else\r
1237         {\r
1238                 myIDMap[idCmd - idCmdFirst] = ShellSubMenu;\r
1239                 myIDMap[idCmd] = ShellSubMenu;\r
1240         }\r
1241         HBITMAP bmp = NULL;\r
1242         if ((fullver < 0x500)||(fullver == 0x500 && !uFlags))\r
1243         {\r
1244                 bmp = IconToBitmap(uIcon);\r
1245                 menuiteminfo.fMask = MIIM_STRING | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_DATA;\r
1246         }\r
1247         else\r
1248         {\r
1249                 menuiteminfo.fMask = MIIM_FTYPE | MIIM_ID | MIIM_SUBMENU | MIIM_DATA | MIIM_BITMAP | MIIM_STRING;\r
1250                 if (bShowIcons)\r
1251                         menuiteminfo.hbmpItem = (fullver >= 0x600) ? IconToBitmapPARGB32(uIcon) : HBMMENU_CALLBACK;\r
1252         }\r
1253         menuiteminfo.hbmpChecked = bmp;\r
1254         menuiteminfo.hbmpUnchecked = bmp;\r
1255         menuiteminfo.hSubMenu = subMenu;\r
1256         menuiteminfo.wID = idCmd++;\r
1257         InsertMenuItem(hMenu, indexMenu++, TRUE, &menuiteminfo);\r
1258 \r
1259         //separator after\r
1260         InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL); idCmd++;\r
1261 \r
1262         //return number of menu items added\r
1263         return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, 0, (USHORT)(idCmd - idCmdFirst)));\r
1264 }\r
1265 \r
1266 \r
1267 // This is called when you invoke a command on the menu:\r
1268 STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)\r
1269 {\r
1270         PreserveChdir preserveChdir;\r
1271         HRESULT hr = E_INVALIDARG;\r
1272         if (lpcmi == NULL)\r
1273                 return hr;\r
1274 \r
1275         std::string command;\r
1276         std::string parent;\r
1277         std::string file;\r
1278 \r
1279         if ((files_.size() > 0)||(folder_.size() > 0))\r
1280         {\r
1281                 UINT idCmd = LOWORD(lpcmi->lpVerb);\r
1282 \r
1283                 if (HIWORD(lpcmi->lpVerb))\r
1284                 {\r
1285                         stdstring verb = stdstring(MultibyteToWide(lpcmi->lpVerb));\r
1286                         std::map<stdstring, UINT_PTR>::const_iterator verb_it = myVerbsMap.lower_bound(verb);\r
1287                         if (verb_it != myVerbsMap.end() && verb_it->first == verb)\r
1288                                 idCmd = verb_it->second;\r
1289                         else\r
1290                                 return hr;\r
1291                 }\r
1292 \r
1293                 // See if we have a handler interface for this id\r
1294                 std::map<UINT_PTR, UINT_PTR>::const_iterator id_it = myIDMap.lower_bound(idCmd);\r
1295                 if (id_it != myIDMap.end() && id_it->first == idCmd)\r
1296                 {\r
1297                         STARTUPINFO startup;\r
1298                         PROCESS_INFORMATION process;\r
1299                         memset(&startup, 0, sizeof(startup));\r
1300                         startup.cb = sizeof(startup);\r
1301                         memset(&process, 0, sizeof(process));\r
1302                         CRegStdString tortoiseProcPath(_T("Software\\TortoiseGit\\ProcPath"), _T("TortoiseProc.exe"), false, HKEY_LOCAL_MACHINE);\r
1303                         CRegStdString tortoiseMergePath(_T("Software\\TortoiseGit\\TMergePath"), _T("TortoiseMerge.exe"), false, HKEY_LOCAL_MACHINE);\r
1304 \r
1305                         //TortoiseProc expects a command line of the form:\r
1306                         //"/command:<commandname> /pathfile:<path> /startrev:<startrevision> /endrev:<endrevision> /deletepathfile\r
1307                         // or\r
1308                         //"/command:<commandname> /path:<path> /startrev:<startrevision> /endrev:<endrevision>\r
1309                         //\r
1310                         //* path is a path to a single file/directory for commands which only act on single items (log, checkout, ...)\r
1311                         //* pathfile is a path to a temporary file which contains a list of file paths\r
1312                         stdstring svnCmd = _T(" /command:");\r
1313                         stdstring tempfile;\r
1314                         switch (id_it->second)\r
1315                         {\r
1316                                 //#region case\r
1317                         case ShellMenuCheckout:\r
1318                                 svnCmd += _T("checkout /path:\"");\r
1319                                 svnCmd += folder_;\r
1320                                 svnCmd += _T("\"");\r
1321                                 break;\r
1322                         case ShellMenuUpdate:\r
1323                                 tempfile = WriteFileListToTempFile();\r
1324                                 svnCmd += _T("update /pathfile:\"");\r
1325                                 svnCmd += tempfile;\r
1326                                 svnCmd += _T("\"");\r
1327                                 svnCmd += _T(" /deletepathfile");\r
1328                                 break;\r
1329                         case ShellMenuUpdateExt:\r
1330                                 tempfile = WriteFileListToTempFile();\r
1331                                 svnCmd += _T("update /pathfile:\"");\r
1332                                 svnCmd += tempfile;\r
1333                                 svnCmd += _T("\"");\r
1334                                 svnCmd += _T(" /deletepathfile");\r
1335                                 svnCmd += _T(" /rev");\r
1336                                 break;\r
1337                         case ShellMenuCommit:\r
1338                                 tempfile = WriteFileListToTempFile();\r
1339                                 svnCmd += _T("commit /pathfile:\"");\r
1340                                 svnCmd += tempfile;\r
1341                                 svnCmd += _T("\"");\r
1342                                 svnCmd += _T(" /deletepathfile");\r
1343                                 break;\r
1344                         case ShellMenuAdd:\r
1345                         case ShellMenuAddAsReplacement:\r
1346                                 tempfile = WriteFileListToTempFile();\r
1347                                 svnCmd += _T("add /pathfile:\"");\r
1348                                 svnCmd += tempfile;\r
1349                                 svnCmd += _T("\"");\r
1350                                 svnCmd += _T(" /deletepathfile");\r
1351                                 break;\r
1352                         case ShellMenuIgnore:\r
1353                                 tempfile = WriteFileListToTempFile();\r
1354                                 svnCmd += _T("ignore /pathfile:\"");\r
1355                                 svnCmd += tempfile;\r
1356                                 svnCmd += _T("\"");\r
1357                                 svnCmd += _T(" /deletepathfile");\r
1358                                 break;\r
1359                         case ShellMenuIgnoreCaseSensitive:\r
1360                                 tempfile = WriteFileListToTempFile();\r
1361                                 svnCmd += _T("ignore /pathfile:\"");\r
1362                                 svnCmd += tempfile;\r
1363                                 svnCmd += _T("\"");\r
1364                                 svnCmd += _T(" /deletepathfile");\r
1365                                 svnCmd += _T(" /onlymask");\r
1366                                 break;\r
1367                         case ShellMenuUnIgnore:\r
1368                                 tempfile = WriteFileListToTempFile();\r
1369                                 svnCmd += _T("unignore /pathfile:\"");\r
1370                                 svnCmd += tempfile;\r
1371                                 svnCmd += _T("\"");\r
1372                                 svnCmd += _T(" /deletepathfile");\r
1373                                 break;\r
1374                         case ShellMenuUnIgnoreCaseSensitive:\r
1375                                 tempfile = WriteFileListToTempFile();\r
1376                                 svnCmd += _T("unignore /pathfile:\"");\r
1377                                 svnCmd += tempfile;\r
1378                                 svnCmd += _T("\"");\r
1379                                 svnCmd += _T(" /deletepathfile");\r
1380                                 svnCmd += _T(" /onlymask");\r
1381                                 break;\r
1382                         case ShellMenuRevert:\r
1383                                 tempfile = WriteFileListToTempFile();\r
1384                                 svnCmd += _T("revert /pathfile:\"");\r
1385                                 svnCmd += tempfile;\r
1386                                 svnCmd += _T("\"");\r
1387                                 svnCmd += _T(" /deletepathfile");\r
1388                                 break;\r
1389                         case ShellMenuDelUnversioned:\r
1390                                 svnCmd += _T("delunversioned /path:\"");\r
1391                                 svnCmd += folder_;\r
1392                                 svnCmd += _T("\"");\r
1393                                 break;\r
1394                         case ShellMenuCleanup:\r
1395                                 tempfile = WriteFileListToTempFile();\r
1396                                 svnCmd += _T("cleanup /pathfile:\"");\r
1397                                 svnCmd += tempfile;\r
1398                                 svnCmd += _T("\"");\r
1399                                 svnCmd += _T(" /deletepathfile");\r
1400                                 break;\r
1401                         case ShellMenuResolve:\r
1402                                 tempfile = WriteFileListToTempFile();\r
1403                                 svnCmd += _T("resolve /pathfile:\"");\r
1404                                 svnCmd += tempfile;\r
1405                                 svnCmd += _T("\"");\r
1406                                 svnCmd += _T(" /deletepathfile");\r
1407                                 break;\r
1408                         case ShellMenuSwitch:\r
1409                                 svnCmd += _T("switch /path:\"");\r
1410                                 if (files_.size() > 0)\r
1411                                         svnCmd += files_.front();\r
1412                                 else\r
1413                                         svnCmd += folder_;\r
1414                                 svnCmd += _T("\"");\r
1415                                 break;\r
1416                         case ShellMenuImport:\r
1417                                 svnCmd += _T("import /path:\"");\r
1418                                 svnCmd += folder_;\r
1419                                 svnCmd += _T("\"");\r
1420                                 break;\r
1421                         case ShellMenuExport:\r
1422                                 svnCmd += _T("export /path:\"");\r
1423                                 svnCmd += folder_;\r
1424                                 svnCmd += _T("\"");\r
1425                                 break;\r
1426                         case ShellMenuAbout:\r
1427                                 svnCmd += _T("about");\r
1428                                 break;\r
1429                         case ShellMenuCreateRepos:\r
1430                                 svnCmd += _T("repocreate /path:\"");\r
1431                                 svnCmd += folder_;\r
1432                                 svnCmd += _T("\"");\r
1433                                 break;\r
1434                         case ShellMenuMerge:\r
1435                                 svnCmd += _T("merge /path:\"");\r
1436                                 if (files_.size() > 0)\r
1437                                         svnCmd += files_.front();\r
1438                                 else\r
1439                                         svnCmd += folder_;\r
1440                                 svnCmd += _T("\"");\r
1441                                 break;\r
1442                         case ShellMenuMergeAll:\r
1443                                 svnCmd += _T("mergeall /path:\"");\r
1444                                 if (files_.size() > 0)\r
1445                                         svnCmd += files_.front();\r
1446                                 else\r
1447                                         svnCmd += folder_;\r
1448                                 svnCmd += _T("\"");\r
1449                                 break;\r
1450                         case ShellMenuCopy:\r
1451                                 svnCmd += _T("copy /path:\"");\r
1452                                 if (files_.size() > 0)\r
1453                                         svnCmd += files_.front();\r
1454                                 else\r
1455                                         svnCmd += folder_;\r
1456                                 svnCmd += _T("\"");\r
1457                                 break;\r
1458                         case ShellMenuSettings:\r
1459                                 svnCmd += _T("settings");\r
1460                                 break;\r
1461                         case ShellMenuHelp:\r
1462                                 svnCmd += _T("help");\r
1463                                 break;\r
1464                         case ShellMenuRename:\r
1465                                 svnCmd += _T("rename /path:\"");\r
1466                                 if (files_.size() > 0)\r
1467                                         svnCmd += files_.front();\r
1468                                 else\r
1469                                         svnCmd += folder_;\r
1470                                 svnCmd += _T("\"");\r
1471                                 break;\r
1472                         case ShellMenuRemove:\r
1473                                 tempfile = WriteFileListToTempFile();\r
1474                                 svnCmd += _T("remove /pathfile:\"");\r
1475                                 svnCmd += tempfile;\r
1476                                 svnCmd += _T("\"");\r
1477                                 svnCmd += _T(" /deletepathfile");\r
1478                                 break;\r
1479                         case ShellMenuRemoveKeep:\r
1480                                 tempfile = WriteFileListToTempFile();\r
1481                                 svnCmd += _T("remove /pathfile:\"");\r
1482                                 svnCmd += tempfile;\r
1483                                 svnCmd += _T("\"");\r
1484                                 svnCmd += _T(" /deletepathfile");\r
1485                                 svnCmd += _T(" /keep");\r
1486                                 break;\r
1487                         case ShellMenuDiff:\r
1488                                 svnCmd += _T("diff /path:\"");\r
1489                                 if (files_.size() == 1)\r
1490                                         svnCmd += files_.front();\r
1491                                 else if (files_.size() == 2)\r
1492                                 {\r
1493                                         std::vector<stdstring>::iterator I = files_.begin();\r
1494                                         svnCmd += *I;\r
1495                                         I++;\r
1496                                         svnCmd += _T("\" /path2:\"");\r
1497                                         svnCmd += *I;\r
1498                                 }\r
1499                                 else\r
1500                                         svnCmd += folder_;\r
1501                                 svnCmd += _T("\"");\r
1502                                 if (GetAsyncKeyState(VK_SHIFT) & 0x8000)\r
1503                                         svnCmd += _T(" /alternative");\r
1504                                 break;\r
1505                         case ShellMenuPrevDiff:\r
1506                                 svnCmd += _T("prevdiff /path:\"");\r
1507                                 if (files_.size() == 1)\r
1508                                         svnCmd += files_.front();\r
1509                                 else\r
1510                                         svnCmd += folder_;\r
1511                                 svnCmd += _T("\"");\r
1512                                 if (GetAsyncKeyState(VK_SHIFT) & 0x8000)\r
1513                                         svnCmd += _T(" /alternative");\r
1514                                 break;\r
1515                         case ShellMenuUrlDiff:\r
1516                                 svnCmd += _T("urldiff /path:\"");\r
1517                                 if (files_.size() == 1)\r
1518                                         svnCmd += files_.front();\r
1519                                 else\r
1520                                         svnCmd += folder_;\r
1521                                 svnCmd += _T("\"");\r
1522                                 break;\r
1523                         case ShellMenuDropCopyAdd:\r
1524                                 tempfile = WriteFileListToTempFile();\r
1525                                 svnCmd += _T("dropcopyadd /pathfile:\"");\r
1526                                 svnCmd += tempfile;\r
1527                                 svnCmd += _T("\"");\r
1528                                 svnCmd += _T(" /deletepathfile");\r
1529                                 svnCmd += _T(" /droptarget:\"");\r
1530                                 svnCmd += folder_;\r
1531                                 svnCmd += _T("\"";)\r
1532                                         break;\r
1533                         case ShellMenuDropCopy:\r
1534                                 tempfile = WriteFileListToTempFile();\r
1535                                 svnCmd += _T("dropcopy /pathfile:\"");\r
1536                                 svnCmd += tempfile;\r
1537                                 svnCmd += _T("\"");\r
1538                                 svnCmd += _T(" /deletepathfile");\r
1539                                 svnCmd += _T(" /droptarget:\"");\r
1540                                 svnCmd += folder_;\r
1541                                 svnCmd += _T("\"";)\r
1542                                         break;\r
1543                         case ShellMenuDropCopyRename:\r
1544                                 tempfile = WriteFileListToTempFile();\r
1545                                 svnCmd += _T("dropcopy /pathfile:\"");\r
1546                                 svnCmd += tempfile;\r
1547                                 svnCmd += _T("\"");\r
1548                                 svnCmd += _T(" /deletepathfile");\r
1549                                 svnCmd += _T(" /droptarget:\"");\r
1550                                 svnCmd += folder_;\r
1551                                 svnCmd += _T("\" /rename";)\r
1552                                         break;\r
1553                         case ShellMenuDropMove:\r
1554                                 tempfile = WriteFileListToTempFile();\r
1555                                 svnCmd += _T("dropmove /pathfile:\"");\r
1556                                 svnCmd += tempfile;\r
1557                                 svnCmd += _T("\"");\r
1558                                 svnCmd += _T(" /deletepathfile");\r
1559                                 svnCmd += _T(" /droptarget:\"");\r
1560                                 svnCmd += folder_;\r
1561                                 svnCmd += _T("\"");\r
1562                                 break;\r
1563                         case ShellMenuDropMoveRename:\r
1564                                 tempfile = WriteFileListToTempFile();\r
1565                                 svnCmd += _T("dropmove /pathfile:\"");\r
1566                                 svnCmd += tempfile;\r
1567                                 svnCmd += _T("\"");\r
1568                                 svnCmd += _T(" /deletepathfile");\r
1569                                 svnCmd += _T(" /droptarget:\"");\r
1570                                 svnCmd += folder_;\r
1571                                 svnCmd += _T("\" /rename";)\r
1572                                 break;\r
1573                         case ShellMenuDropExport:\r
1574                                 tempfile = WriteFileListToTempFile();\r
1575                                 svnCmd += _T("dropexport /pathfile:\"");\r
1576                                 svnCmd += tempfile;\r
1577                                 svnCmd += _T("\"");\r
1578                                 svnCmd += _T(" /deletepathfile");\r
1579                                 svnCmd += _T(" /droptarget:\"");\r
1580                                 svnCmd += folder_;\r
1581                                 svnCmd += _T("\"");\r
1582                                 break;\r
1583                         case ShellMenuDropExportExtended:\r
1584                                 tempfile = WriteFileListToTempFile();\r
1585                                 svnCmd += _T("dropexport /pathfile:\"");\r
1586                                 svnCmd += tempfile;\r
1587                                 svnCmd += _T("\"");\r
1588                                 svnCmd += _T(" /deletepathfile");\r
1589                                 svnCmd += _T(" /droptarget:\"");\r
1590                                 svnCmd += folder_;\r
1591                                 svnCmd += _T("\"");\r
1592                                 svnCmd += _T(" /extended");\r
1593                                 break;\r
1594                         case ShellMenuLog:\r
1595                                 svnCmd += _T("log /path:\"");\r
1596                                 if (files_.size() > 0)\r
1597                                         svnCmd += files_.front();\r
1598                                 else\r
1599                                         svnCmd += folder_;\r
1600                                 svnCmd += _T("\"");\r
1601                                 break;\r
1602                         case ShellMenuConflictEditor:\r
1603                                 svnCmd += _T("conflicteditor /path:\"");\r
1604                                 if (files_.size() > 0)\r
1605                                         svnCmd += files_.front();\r
1606                                 else\r
1607                                         svnCmd += folder_;\r
1608                                 svnCmd += _T("\"");\r
1609                                 break;\r
1610                         case ShellMenuRelocate:\r
1611                                 svnCmd += _T("relocate /path:\"");\r
1612                                 if (files_.size() > 0)\r
1613                                         svnCmd += files_.front();\r
1614                                 else\r
1615                                         svnCmd += folder_;\r
1616                                 svnCmd += _T("\"");\r
1617                                 break;\r
1618                         case ShellMenuShowChanged:\r
1619                                 if (files_.size() > 1)\r
1620                 {\r
1621                                     tempfile = WriteFileListToTempFile();\r
1622                                     svnCmd += _T("repostatus /pathfile:\"");\r
1623                                     svnCmd += tempfile;\r
1624                                 svnCmd += _T("\"");\r
1625                                 svnCmd += _T(" /deletepathfile");\r
1626                 }\r
1627                 else\r
1628                 {\r
1629                     svnCmd += _T("repostatus /path:\"");\r
1630                                     if (files_.size() > 0)\r
1631                                             svnCmd += files_.front();\r
1632                                     else\r
1633                                             svnCmd += folder_;\r
1634                                 svnCmd += _T("\"");\r
1635                 }\r
1636                                 break;\r
1637                         case ShellMenuRepoBrowse:\r
1638                                 svnCmd += _T("repobrowser /path:\"");\r
1639                                 if (files_.size() > 0)\r
1640                                         svnCmd += files_.front();\r
1641                                 else\r
1642                                         svnCmd += folder_;\r
1643                                 svnCmd += _T("\"");\r
1644                                 break;\r
1645                         case ShellMenuBlame:\r
1646                                 svnCmd += _T("blame /path:\"");\r
1647                                 if (files_.size() > 0)\r
1648                                         svnCmd += files_.front();\r
1649                                 else\r
1650                                         svnCmd += folder_;\r
1651                                 svnCmd += _T("\"");\r
1652                                 break;\r
1653                         case ShellMenuCreatePatch:\r
1654                                 tempfile = WriteFileListToTempFile();\r
1655                                 svnCmd += _T("createpatch /pathfile:\"");\r
1656                                 svnCmd += tempfile;\r
1657                                 svnCmd += _T("\"");\r
1658                                 svnCmd += _T(" /deletepathfile");\r
1659                                 break;\r
1660                         case ShellMenuApplyPatch:\r
1661                                 if ((itemStates & ITEMIS_PATCHINCLIPBOARD) && ((~itemStates) & ITEMIS_PATCHFILE))\r
1662                                 {\r
1663                                         // if there's a patch file in the clipboard, we save it\r
1664                                         // to a temporary file and tell TortoiseMerge to use that one\r
1665                                         UINT cFormat = RegisterClipboardFormat(_T("TGIT_UNIFIEDDIFF"));\r
1666                                         if ((cFormat)&&(OpenClipboard(NULL)))\r
1667                                         { \r
1668                                                 HGLOBAL hglb = GetClipboardData(cFormat); \r
1669                                                 LPCSTR lpstr = (LPCSTR)GlobalLock(hglb); \r
1670 \r
1671                                                 DWORD len = GetTempPath(0, NULL);\r
1672                                                 TCHAR * path = new TCHAR[len+1];\r
1673                                                 TCHAR * tempF = new TCHAR[len+100];\r
1674                                                 GetTempPath (len+1, path);\r
1675                                                 GetTempFileName (path, TEXT("git"), 0, tempF);\r
1676                                                 std::wstring sTempFile = std::wstring(tempF);\r
1677                                                 delete [] path;\r
1678                                                 delete [] tempF;\r
1679 \r
1680                                                 FILE * outFile;\r
1681                                                 size_t patchlen = strlen(lpstr);\r
1682                                                 _tfopen_s(&outFile, sTempFile.c_str(), _T("wb"));\r
1683                                                 if(outFile)\r
1684                                                 {\r
1685                                                         size_t size = fwrite(lpstr, sizeof(char), patchlen, outFile);\r
1686                                                         if (size == patchlen)\r
1687                                                         {\r
1688                                                                 itemStates |= ITEMIS_PATCHFILE;\r
1689                                                                 files_.clear();\r
1690                                                                 files_.push_back(sTempFile);\r
1691                                                         }\r
1692                                                         fclose(outFile);\r
1693                                                 }\r
1694                                                 GlobalUnlock(hglb); \r
1695                                                 CloseClipboard(); \r
1696                                         } \r
1697                                 }\r
1698                                 if (itemStates & ITEMIS_PATCHFILE)\r
1699                                 {\r
1700                                         svnCmd = _T(" /diff:\"");\r
1701                                         if (files_.size() > 0)\r
1702                                         {\r
1703                                                 svnCmd += files_.front();\r
1704                                                 if (itemStatesFolder & ITEMIS_FOLDERINSVN)\r
1705                                                 {\r
1706                                                         svnCmd += _T("\" /patchpath:\"");\r
1707                                                         svnCmd += folder_;\r
1708                                                 }\r
1709                                         }\r
1710                                         else\r
1711                                                 svnCmd += folder_;\r
1712                                         if (itemStates & ITEMIS_INVERSIONEDFOLDER)\r
1713                                                 svnCmd += _T("\" /wc");\r
1714                                         else\r
1715                                                 svnCmd += _T("\"");\r
1716                                 }\r
1717                                 else\r
1718                                 {\r
1719                                         svnCmd = _T(" /patchpath:\"");\r
1720                                         if (files_.size() > 0)\r
1721                                                 svnCmd += files_.front();\r
1722                                         else\r
1723                                                 svnCmd += folder_;\r
1724                                         svnCmd += _T("\"");\r
1725                                 }\r
1726                                 myIDMap.clear();\r
1727                                 myVerbsIDMap.clear();\r
1728                                 myVerbsMap.clear();\r
1729                                 if (CreateProcess(((stdstring)tortoiseMergePath).c_str(), const_cast<TCHAR*>(svnCmd.c_str()), NULL, NULL, FALSE, 0, 0, 0, &startup, &process)==0)\r
1730                                 {\r
1731                                         LPVOID lpMsgBuf;\r
1732                                         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | \r
1733                                                 FORMAT_MESSAGE_FROM_SYSTEM | \r
1734                                                 FORMAT_MESSAGE_IGNORE_INSERTS,\r
1735                                                 NULL,\r
1736                                                 GetLastError(),\r
1737                                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\r
1738                                                 (LPTSTR) &lpMsgBuf,\r
1739                                                 0,\r
1740                                                 NULL \r
1741                                                 );\r
1742                                         MessageBox( NULL, (LPCTSTR)lpMsgBuf, _T("TortoiseMerge launch failed"), MB_OK | MB_ICONINFORMATION );\r
1743                                         LocalFree( lpMsgBuf );\r
1744                                 }\r
1745                                 CloseHandle(process.hThread);\r
1746                                 CloseHandle(process.hProcess);\r
1747                                 return NOERROR;\r
1748                                 break;\r
1749                         case ShellMenuRevisionGraph:\r
1750                                 svnCmd += _T("revisiongraph /path:\"");\r
1751                                 if (files_.size() > 0)\r
1752                                         svnCmd += files_.front();\r
1753                                 else\r
1754                                         svnCmd += folder_;\r
1755                                 svnCmd += _T("\"");\r
1756                                 break;\r
1757                         case ShellMenuProperties:\r
1758                                 tempfile = WriteFileListToTempFile();\r
1759                                 svnCmd += _T("properties /pathfile:\"");\r
1760                                 svnCmd += tempfile;\r
1761                                 svnCmd += _T("\"");\r
1762                                 svnCmd += _T(" /deletepathfile");\r
1763                                 break;\r
1764                         case ShellMenuClipPaste:\r
1765                                 if (WriteClipboardPathsToTempFile(tempfile))\r
1766                                 {\r
1767                                         bool bCopy = true;\r
1768                                         UINT cPrefDropFormat = RegisterClipboardFormat(_T("Preferred DropEffect"));\r
1769                                         if (cPrefDropFormat)\r
1770                                         {\r
1771                                                 if (OpenClipboard(lpcmi->hwnd))\r
1772                                                 {\r
1773                                                         HGLOBAL hglb = GetClipboardData(cPrefDropFormat);\r
1774                                                         if (hglb)\r
1775                                                         {\r
1776                                                                 DWORD* effect = (DWORD*) GlobalLock(hglb);\r
1777                                                                 if (*effect == DROPEFFECT_MOVE)\r
1778                                                                         bCopy = false;\r
1779                                                                 GlobalUnlock(hglb);\r
1780                                                         }\r
1781                                                         CloseClipboard();\r
1782                                                 }\r
1783                                         }\r
1784 \r
1785                                         if (bCopy)\r
1786                                                 svnCmd += _T("pastecopy /pathfile:\"");\r
1787                                         else\r
1788                                                 svnCmd += _T("pastemove /pathfile:\"");\r
1789                                         svnCmd += tempfile;\r
1790                                         svnCmd += _T("\"");\r
1791                                         svnCmd += _T(" /deletepathfile");\r
1792                                         svnCmd += _T(" /droptarget:\"");\r
1793                                         svnCmd += folder_;\r
1794                                         svnCmd += _T("\"");\r
1795                                 }\r
1796                                 else return NOERROR;\r
1797                                 break;\r
1798                         case ShellMenuClone:\r
1799                                 svnCmd += _T("clone /path:\"");\r
1800                                 svnCmd += folder_;\r
1801                                 svnCmd += _T("\"");\r
1802                                 break;\r
1803                         case ShellMenuPull:\r
1804                                 svnCmd += _T("pull /path:\"");\r
1805                                 if (files_.size() > 0)\r
1806                                         svnCmd += files_.front();\r
1807                                 else\r
1808                                         svnCmd += folder_;\r
1809                                 svnCmd += _T("\"");\r
1810                                 break;\r
1811                         case ShellMenuPush:\r
1812                                 svnCmd += _T("push /path:\"");\r
1813                                 if (files_.size() > 0)\r
1814                                         svnCmd += files_.front();\r
1815                                 else\r
1816                                         svnCmd += folder_;\r
1817                                 svnCmd += _T("\"");\r
1818                                 break;\r
1819                         case ShellMenuBranch:\r
1820                                 svnCmd += _T("branch /path:\"");\r
1821                                 if (files_.size() > 0)\r
1822                                         svnCmd += files_.front();\r
1823                                 else\r
1824                                         svnCmd += folder_;\r
1825                                 svnCmd += _T("\"");\r
1826                                 break;\r
1827                         \r
1828                         case ShellMenuTag:\r
1829                                 svnCmd += _T("tag /path:\"");\r
1830                                 if (files_.size() > 0)\r
1831                                         svnCmd += files_.front();\r
1832                                 else\r
1833                                         svnCmd += folder_;\r
1834                                 svnCmd += _T("\"");\r
1835                                 break;\r
1836 \r
1837                         case ShellMenuFormatPatch:\r
1838                                 svnCmd += _T("formatpatch /path:\"");\r
1839                                 if (files_.size() > 0)\r
1840                                         svnCmd += files_.front();\r
1841                                 else\r
1842                                         svnCmd += folder_;\r
1843                                 svnCmd += _T("\"");\r
1844                                 break;\r
1845 \r
1846                         case ShellMenuImportPatch:\r
1847                                 svnCmd += _T("importpatch /path:\"");\r
1848                                 if (files_.size() > 0)\r
1849                                         svnCmd += files_.front();\r
1850                                 else\r
1851                                         svnCmd += folder_;\r
1852                                 svnCmd += _T("\"");\r
1853                                 break;\r
1854 \r
1855                         case ShellMenuCherryPick:\r
1856                                 svnCmd += _T("cherrypick /path:\"");\r
1857                                 if (files_.size() > 0)\r
1858                                         svnCmd += files_.front();\r
1859                                 else\r
1860                                         svnCmd += folder_;\r
1861                                 svnCmd += _T("\"");\r
1862                                 break;\r
1863                         case ShellMenuFetch:\r
1864                                 svnCmd += _T("fetch /path:\"");\r
1865                                 if (files_.size() > 0)\r
1866                                         svnCmd += files_.front();\r
1867                                 else\r
1868                                         svnCmd += folder_;\r
1869                                 svnCmd += _T("\"");\r
1870                                 break;\r
1871 \r
1872                         default:\r
1873                                 break;\r
1874                                 //#endregion\r
1875                         } // switch (id_it->second) \r
1876                         svnCmd += _T(" /hwnd:");\r
1877                         TCHAR buf[30];\r
1878                         _stprintf_s(buf, 30, _T("%d"), lpcmi->hwnd);\r
1879                         svnCmd += buf;\r
1880                         myIDMap.clear();\r
1881                         myVerbsIDMap.clear();\r
1882                         myVerbsMap.clear();\r
1883                         if (CreateProcess(((stdstring)tortoiseProcPath).c_str(), const_cast<TCHAR*>(svnCmd.c_str()), NULL, NULL, FALSE, 0, 0, 0, &startup, &process)==0)\r
1884                         {\r
1885                                 LPVOID lpMsgBuf;\r
1886                                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | \r
1887                                         FORMAT_MESSAGE_FROM_SYSTEM | \r
1888                                         FORMAT_MESSAGE_IGNORE_INSERTS,\r
1889                                         NULL,\r
1890                                         GetLastError(),\r
1891                                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\r
1892                                         (LPTSTR) &lpMsgBuf,\r
1893                                         0,\r
1894                                         NULL \r
1895                                         );\r
1896                                 MessageBox( NULL, (LPCTSTR)lpMsgBuf, _T("TortoiseProc Launch failed"), MB_OK | MB_ICONINFORMATION );\r
1897                                 LocalFree( lpMsgBuf );\r
1898                         }\r
1899                         CloseHandle(process.hThread);\r
1900                         CloseHandle(process.hProcess);\r
1901                         hr = NOERROR;\r
1902                 } // if (id_it != myIDMap.end() && id_it->first == idCmd) \r
1903         } // if ((files_.size() > 0)||(folder_.size() > 0)) \r
1904         return hr;\r
1905 \r
1906 }\r
1907 \r
1908 // This is for the status bar and things like that:\r
1909 STDMETHODIMP CShellExt::GetCommandString(UINT_PTR idCmd,\r
1910                                          UINT uFlags,\r
1911                                          UINT FAR * /*reserved*/,\r
1912                                          LPSTR pszName,\r
1913                                          UINT cchMax)\r
1914 {\r
1915         PreserveChdir preserveChdir;\r
1916         //do we know the id?\r
1917         std::map<UINT_PTR, UINT_PTR>::const_iterator id_it = myIDMap.lower_bound(idCmd);\r
1918         if (id_it == myIDMap.end() || id_it->first != idCmd)\r
1919         {\r
1920                 return E_INVALIDARG;            //no, we don't\r
1921         }\r
1922 \r
1923         LoadLangDll();\r
1924         HRESULT hr = E_INVALIDARG;\r
1925 \r
1926         MAKESTRING(IDS_MENUDESCDEFAULT);\r
1927         int menuIndex = 0;\r
1928         while (menuInfo[menuIndex].command != ShellMenuLastEntry)\r
1929         {\r
1930                 if (menuInfo[menuIndex].command == (GitCommands)id_it->second)\r
1931                 {\r
1932                         MAKESTRING(menuInfo[menuIndex].menuDescID);\r
1933                         break;\r
1934                 }\r
1935                 menuIndex++;\r
1936         }\r
1937 \r
1938         const TCHAR * desc = stringtablebuffer;\r
1939         switch(uFlags)\r
1940         {\r
1941         case GCS_HELPTEXTA:\r
1942                 {\r
1943                         std::string help = WideToMultibyte(desc);\r
1944                         lstrcpynA(pszName, help.c_str(), cchMax);\r
1945                         hr = S_OK;\r
1946                         break; \r
1947                 }\r
1948         case GCS_HELPTEXTW: \r
1949                 {\r
1950                         wide_string help = desc;\r
1951                         lstrcpynW((LPWSTR)pszName, help.c_str(), cchMax); \r
1952                         hr = S_OK;\r
1953                         break; \r
1954                 }\r
1955         case GCS_VERBA:\r
1956                 {\r
1957                         std::map<UINT_PTR, stdstring>::const_iterator verb_id_it = myVerbsIDMap.lower_bound(idCmd);\r
1958                         if (verb_id_it != myVerbsIDMap.end() && verb_id_it->first == idCmd)\r
1959                         {\r
1960                                 std::string help = WideToMultibyte(verb_id_it->second);\r
1961                                 lstrcpynA(pszName, help.c_str(), cchMax);\r
1962                                 hr = S_OK;\r
1963                         }\r
1964                 }\r
1965                 break;\r
1966         case GCS_VERBW:\r
1967                 {\r
1968                         std::map<UINT_PTR, stdstring>::const_iterator verb_id_it = myVerbsIDMap.lower_bound(idCmd);\r
1969                         if (verb_id_it != myVerbsIDMap.end() && verb_id_it->first == idCmd)\r
1970                         {\r
1971                                 wide_string help = verb_id_it->second;\r
1972                                 ATLTRACE("verb : %ws\n", help.c_str());\r
1973                                 lstrcpynW((LPWSTR)pszName, help.c_str(), cchMax); \r
1974                                 hr = S_OK;\r
1975                         }\r
1976                 }\r
1977                 break;\r
1978         }\r
1979         return hr;\r
1980 }\r
1981 \r
1982 STDMETHODIMP CShellExt::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)\r
1983 {\r
1984         LRESULT res;\r
1985         return HandleMenuMsg2(uMsg, wParam, lParam, &res);\r
1986 }\r
1987 \r
1988 STDMETHODIMP CShellExt::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult)\r
1989 {\r
1990         PreserveChdir preserveChdir;\r
1991 \r
1992         LRESULT res;\r
1993         if (pResult == NULL)\r
1994                 pResult = &res;\r
1995         *pResult = FALSE;\r
1996 \r
1997         LoadLangDll();\r
1998         switch (uMsg)\r
1999         {\r
2000         case WM_MEASUREITEM:\r
2001                 {\r
2002                         MEASUREITEMSTRUCT* lpmis = (MEASUREITEMSTRUCT*)lParam;\r
2003                         if (lpmis==NULL)\r
2004                                 break;\r
2005                         lpmis->itemWidth += 2;\r
2006                         if (lpmis->itemHeight < 16)\r
2007                                 lpmis->itemHeight = 16;\r
2008                         *pResult = TRUE;\r
2009                 }\r
2010                 break;\r
2011         case WM_DRAWITEM:\r
2012                 {\r
2013                         LPCTSTR resource;\r
2014                         DRAWITEMSTRUCT* lpdis = (DRAWITEMSTRUCT*)lParam;\r
2015                         if ((lpdis==NULL)||(lpdis->CtlType != ODT_MENU))\r
2016                                 return S_OK;            //not for a menu\r
2017                         resource = GetMenuTextFromResource(myIDMap[lpdis->itemID]);\r
2018                         if (resource == NULL)\r
2019                                 return S_OK;\r
2020                         HICON hIcon = (HICON)LoadImage(g_hResInst, resource, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);\r
2021                         if (hIcon == NULL)\r
2022                                 return S_OK;\r
2023                         DrawIconEx(lpdis->hDC,\r
2024                                 lpdis->rcItem.left - 16,\r
2025                                 lpdis->rcItem.top + (lpdis->rcItem.bottom - lpdis->rcItem.top - 16) / 2,\r
2026                                 hIcon, 16, 16,\r
2027                                 0, NULL, DI_NORMAL);\r
2028                         DestroyIcon(hIcon);\r
2029                         *pResult = TRUE;\r
2030                 }\r
2031                 break;\r
2032         case WM_MENUCHAR:\r
2033                 {\r
2034                         LPCTSTR resource;\r
2035                         TCHAR *szItem;\r
2036                         if (HIWORD(wParam) != MF_POPUP)\r
2037                                 return NOERROR;\r
2038                         int nChar = LOWORD(wParam);\r
2039                         if (_istascii((wint_t)nChar) && _istupper((wint_t)nChar))\r
2040                                 nChar = tolower(nChar);\r
2041                         // we have the char the user pressed, now search that char in all our\r
2042                         // menu items\r
2043                         std::vector<int> accmenus;\r
2044                         for (std::map<UINT_PTR, UINT_PTR>::iterator It = mySubMenuMap.begin(); It != mySubMenuMap.end(); ++It)\r
2045                         {\r
2046                                 resource = GetMenuTextFromResource(mySubMenuMap[It->first]);\r
2047                                 if (resource == NULL)\r
2048                                         continue;\r
2049                                 szItem = stringtablebuffer;\r
2050                                 TCHAR * amp = _tcschr(szItem, '&');\r
2051                                 if (amp == NULL)\r
2052                                         continue;\r
2053                                 amp++;\r
2054                                 int ampChar = LOWORD(*amp);\r
2055                                 if (_istascii((wint_t)ampChar) && _istupper((wint_t)ampChar))\r
2056                                         ampChar = tolower(ampChar);\r
2057                                 if (ampChar == nChar)\r
2058                                 {\r
2059                                         // yep, we found a menu which has the pressed key\r
2060                                         // as an accelerator. Add that menu to the list to\r
2061                                         // process later.\r
2062                                         accmenus.push_back(It->first);\r
2063                                 }\r
2064                         }\r
2065                         if (accmenus.size() == 0)\r
2066                         {\r
2067                                 // no menu with that accelerator key.\r
2068                                 *pResult = MAKELONG(0, MNC_IGNORE);\r
2069                                 return NOERROR;\r
2070                         }\r
2071                         if (accmenus.size() == 1)\r
2072                         {\r
2073                                 // Only one menu with that accelerator key. We're lucky!\r
2074                                 // So just execute that menu entry.\r
2075                                 *pResult = MAKELONG(accmenus[0], MNC_EXECUTE);\r
2076                                 return NOERROR;\r
2077                         }\r
2078                         if (accmenus.size() > 1)\r
2079                         {\r
2080                                 // we have more than one menu item with this accelerator key!\r
2081                                 MENUITEMINFO mif;\r
2082                                 mif.cbSize = sizeof(MENUITEMINFO);\r
2083                                 mif.fMask = MIIM_STATE;\r
2084                                 for (std::vector<int>::iterator it = accmenus.begin(); it != accmenus.end(); ++it)\r
2085                                 {\r
2086                                         GetMenuItemInfo((HMENU)lParam, *it, TRUE, &mif);\r
2087                                         if (mif.fState == MFS_HILITE)\r
2088                                         {\r
2089                                                 // this is the selected item, so select the next one\r
2090                                                 ++it;\r
2091                                                 if (it == accmenus.end())\r
2092                                                         *pResult = MAKELONG(accmenus[0], MNC_SELECT);\r
2093                                                 else\r
2094                                                         *pResult = MAKELONG(*it, MNC_SELECT);\r
2095                                                 return NOERROR;\r
2096                                         }\r
2097                                 }\r
2098                                 *pResult = MAKELONG(accmenus[0], MNC_SELECT);\r
2099                         }\r
2100                 }\r
2101                 break;\r
2102         default:\r
2103                 return NOERROR;\r
2104         }\r
2105 \r
2106         return NOERROR;\r
2107 }\r
2108 \r
2109 LPCTSTR CShellExt::GetMenuTextFromResource(int id)\r
2110 {\r
2111         TCHAR textbuf[255];\r
2112         LPCTSTR resource = NULL;\r
2113         unsigned __int64 layout = g_ShellCache.GetMenuLayout();\r
2114         space = 6;\r
2115 \r
2116         int menuIndex = 0;\r
2117         while (menuInfo[menuIndex].command != ShellMenuLastEntry)\r
2118         {\r
2119                 if (menuInfo[menuIndex].command == id)\r
2120                 {\r
2121                         MAKESTRING(menuInfo[menuIndex].menuTextID);\r
2122                         resource = MAKEINTRESOURCE(menuInfo[menuIndex].iconID);\r
2123                         switch (id)\r
2124                         {\r
2125                         case ShellSubMenuMultiple:\r
2126                         case ShellSubMenuLink:\r
2127                         case ShellSubMenuFolder:\r
2128                         case ShellSubMenuFile:\r
2129                         case ShellSubMenu:\r
2130                                 space = 0;\r
2131                                 break;\r
2132                         default:\r
2133                                 space = layout & menuInfo[menuIndex].menuID ? 0 : 6;\r
2134                                 if (layout & (menuInfo[menuIndex].menuID)) \r
2135                                 {\r
2136                                         _tcscpy_s(textbuf, 255, _T("Git "));\r
2137                                         _tcscat_s(textbuf, 255, stringtablebuffer);\r
2138                                         _tcscpy_s(stringtablebuffer, 255, textbuf);\r
2139                                 }\r
2140                                 break;\r
2141                         }\r
2142                         return resource;\r
2143                 }\r
2144                 menuIndex++;\r
2145         }\r
2146         return NULL;\r
2147 }\r
2148 \r
2149 bool CShellExt::IsIllegalFolder(std::wstring folder, int * cslidarray)\r
2150 {\r
2151         int i=0;\r
2152         TCHAR buf[MAX_PATH];    //MAX_PATH ok, since SHGetSpecialFolderPath doesn't return the required buffer length!\r
2153         LPITEMIDLIST pidl = NULL;\r
2154         while (cslidarray[i])\r
2155         {\r
2156                 ++i;\r
2157                 pidl = NULL;\r
2158                 if (SHGetFolderLocation(NULL, cslidarray[i-1], NULL, 0, &pidl)!=S_OK)\r
2159                         continue;\r
2160                 if (!SHGetPathFromIDList(pidl, buf))\r
2161                 {\r
2162                         // not a file system path, definitely illegal for our use\r
2163                         CoTaskMemFree(pidl);\r
2164                         continue;\r
2165                 }\r
2166                 CoTaskMemFree(pidl);\r
2167                 if (_tcslen(buf)==0)\r
2168                         continue;\r
2169                 if (_tcscmp(buf, folder.c_str())==0)\r
2170                         return true;\r
2171         }\r
2172         return false;\r
2173 }\r
2174 \r
2175 void CShellExt::InsertIgnoreSubmenus(UINT &idCmd, UINT idCmdFirst, HMENU hMenu, HMENU subMenu, UINT &indexMenu, int &indexSubMenu, unsigned __int64 topmenu, bool bShowIcons)\r
2176 {\r
2177         HMENU ignoresubmenu = NULL;\r
2178         int indexignoresub = 0;\r
2179         bool bShowIgnoreMenu = false;\r
2180         TCHAR maskbuf[MAX_PATH];                // MAX_PATH is ok, since this only holds a filename\r
2181         TCHAR ignorepath[MAX_PATH];             // MAX_PATH is ok, since this only holds a filename\r
2182         if (files_.size() == 0)\r
2183                 return;\r
2184         UINT icon = bShowIcons ? IDI_IGNORE : 0;\r
2185 \r
2186         std::vector<stdstring>::iterator I = files_.begin();\r
2187         if (_tcsrchr(I->c_str(), '\\'))\r
2188                 _tcscpy_s(ignorepath, MAX_PATH, _tcsrchr(I->c_str(), '\\')+1);\r
2189         else\r
2190                 _tcscpy_s(ignorepath, MAX_PATH, I->c_str());\r
2191         if ((itemStates & ITEMIS_IGNORED)&&(ignoredprops.size() > 0))\r
2192         {\r
2193                 // check if the item name is ignored or the mask\r
2194                 size_t p = 0;\r
2195                 while ( (p=ignoredprops.find( ignorepath,p )) != -1 )\r
2196                 {\r
2197                         if ( (p==0 || ignoredprops[p-1]==TCHAR('\n'))\r
2198                                 && (p+_tcslen(ignorepath)==ignoredprops.length() || ignoredprops[p+_tcslen(ignorepath)+1]==TCHAR('\n')) )\r
2199                         {\r
2200                                 break;\r
2201                         }\r
2202                         p++;\r
2203                 }\r
2204                 if (p!=-1)\r
2205                 {\r
2206                         ignoresubmenu = CreateMenu();\r
2207                         InsertMenu(ignoresubmenu, indexignoresub++, MF_BYPOSITION | MF_STRING , idCmd, ignorepath);\r
2208                         stdstring verb = stdstring(ignorepath);\r
2209                         myVerbsMap[verb] = idCmd - idCmdFirst;\r
2210                         myVerbsMap[verb] = idCmd;\r
2211                         myVerbsIDMap[idCmd - idCmdFirst] = verb;\r
2212                         myVerbsIDMap[idCmd] = verb;\r
2213                         myIDMap[idCmd - idCmdFirst] = ShellMenuUnIgnore;\r
2214                         myIDMap[idCmd++] = ShellMenuUnIgnore;\r
2215                         bShowIgnoreMenu = true;\r
2216                 }\r
2217                 _tcscpy_s(maskbuf, MAX_PATH, _T("*"));\r
2218                 if (_tcsrchr(ignorepath, '.'))\r
2219                 {\r
2220                         _tcscat_s(maskbuf, MAX_PATH, _tcsrchr(ignorepath, '.'));\r
2221                         p = ignoredprops.find(maskbuf);\r
2222                         if ((p!=-1) &&\r
2223                                 ((ignoredprops.compare(maskbuf)==0) || (ignoredprops.find('\n', p)==p+_tcslen(maskbuf)+1) || (ignoredprops.rfind('\n', p)==p-1)))\r
2224                         {\r
2225                                 if (ignoresubmenu==NULL)\r
2226                                         ignoresubmenu = CreateMenu();\r
2227 \r
2228                                 InsertMenu(ignoresubmenu, indexignoresub++, MF_BYPOSITION | MF_STRING , idCmd, maskbuf);\r
2229                                 stdstring verb = stdstring(maskbuf);\r
2230                                 myVerbsMap[verb] = idCmd - idCmdFirst;\r
2231                                 myVerbsMap[verb] = idCmd;\r
2232                                 myVerbsIDMap[idCmd - idCmdFirst] = verb;\r
2233                                 myVerbsIDMap[idCmd] = verb;\r
2234                                 myIDMap[idCmd - idCmdFirst] = ShellMenuUnIgnoreCaseSensitive;\r
2235                                 myIDMap[idCmd++] = ShellMenuUnIgnoreCaseSensitive;\r
2236                                 bShowIgnoreMenu = true;\r
2237                         }\r
2238                 }\r
2239         }\r
2240         else if ((itemStates & ITEMIS_IGNORED) == 0)\r
2241         {\r
2242                 bShowIgnoreMenu = true;\r
2243                 ignoresubmenu = CreateMenu();\r
2244                 if (itemStates & ITEMIS_ONLYONE)\r
2245                 {\r
2246                         InsertMenu(ignoresubmenu, indexignoresub++, MF_BYPOSITION | MF_STRING , idCmd, ignorepath);\r
2247                         myIDMap[idCmd - idCmdFirst] = ShellMenuIgnore;\r
2248                         myIDMap[idCmd++] = ShellMenuIgnore;\r
2249 \r
2250                         _tcscpy_s(maskbuf, MAX_PATH, _T("*"));\r
2251                         if (_tcsrchr(ignorepath, '.'))\r
2252                         {\r
2253                                 _tcscat_s(maskbuf, MAX_PATH, _tcsrchr(ignorepath, '.'));\r
2254                                 InsertMenu(ignoresubmenu, indexignoresub++, MF_BYPOSITION | MF_STRING , idCmd, maskbuf);\r
2255                                 stdstring verb = stdstring(maskbuf);\r
2256                                 myVerbsMap[verb] = idCmd - idCmdFirst;\r
2257                                 myVerbsMap[verb] = idCmd;\r
2258                                 myVerbsIDMap[idCmd - idCmdFirst] = verb;\r
2259                                 myVerbsIDMap[idCmd] = verb;\r
2260                                 myIDMap[idCmd - idCmdFirst] = ShellMenuIgnoreCaseSensitive;\r
2261                                 myIDMap[idCmd++] = ShellMenuIgnoreCaseSensitive;\r
2262                         }\r
2263                 }\r
2264                 else\r
2265                 {\r
2266                         MAKESTRING(IDS_MENUIGNOREMULTIPLE);\r
2267                         _stprintf_s(ignorepath, MAX_PATH, stringtablebuffer, files_.size());\r
2268                         InsertMenu(ignoresubmenu, indexignoresub++, MF_BYPOSITION | MF_STRING , idCmd, ignorepath);\r
2269                         stdstring verb = stdstring(ignorepath);\r
2270                         myVerbsMap[verb] = idCmd - idCmdFirst;\r
2271                         myVerbsMap[verb] = idCmd;\r
2272                         myVerbsIDMap[idCmd - idCmdFirst] = verb;\r
2273                         myVerbsIDMap[idCmd] = verb;\r
2274                         myIDMap[idCmd - idCmdFirst] = ShellMenuIgnore;\r
2275                         myIDMap[idCmd++] = ShellMenuIgnore;\r
2276 \r
2277                         MAKESTRING(IDS_MENUIGNOREMULTIPLEMASK);\r
2278                         _stprintf_s(ignorepath, MAX_PATH, stringtablebuffer, files_.size());\r
2279                         InsertMenu(ignoresubmenu, indexignoresub++, MF_BYPOSITION | MF_STRING , idCmd, ignorepath);\r
2280                         verb = stdstring(ignorepath);\r
2281                         myVerbsMap[verb] = idCmd - idCmdFirst;\r
2282                         myVerbsMap[verb] = idCmd;\r
2283                         myVerbsIDMap[idCmd - idCmdFirst] = verb;\r
2284                         myVerbsIDMap[idCmd] = verb;\r
2285                         myIDMap[idCmd - idCmdFirst] = ShellMenuIgnoreCaseSensitive;\r
2286                         myIDMap[idCmd++] = ShellMenuIgnoreCaseSensitive;\r
2287                 }\r
2288         }\r
2289 \r
2290         if (bShowIgnoreMenu)\r
2291         {\r
2292                 MENUITEMINFO menuiteminfo;\r
2293                 SecureZeroMemory(&menuiteminfo, sizeof(menuiteminfo));\r
2294                 menuiteminfo.cbSize = sizeof(menuiteminfo);\r
2295                 menuiteminfo.fMask = MIIM_FTYPE | MIIM_ID | MIIM_SUBMENU | MIIM_DATA | MIIM_BITMAP | MIIM_STRING;\r
2296                 menuiteminfo.fType = MFT_STRING;\r
2297                 HBITMAP bmp = (fullver >= 0x600) ? IconToBitmapPARGB32(icon) : IconToBitmap(icon);\r
2298                 if (icon)\r
2299                         menuiteminfo.hbmpItem = (fullver >= 0x600) ? bmp : HBMMENU_CALLBACK;\r
2300                 menuiteminfo.hbmpChecked = bmp;\r
2301                 menuiteminfo.hbmpUnchecked = bmp;\r
2302                 menuiteminfo.hSubMenu = ignoresubmenu;\r
2303                 menuiteminfo.wID = idCmd;\r
2304                 SecureZeroMemory(stringtablebuffer, sizeof(stringtablebuffer));\r
2305                 if (itemStates & ITEMIS_IGNORED)\r
2306                         GetMenuTextFromResource(ShellMenuUnIgnoreSub);\r
2307                 else\r
2308                         GetMenuTextFromResource(ShellMenuIgnoreSub);\r
2309                 menuiteminfo.dwTypeData = stringtablebuffer;\r
2310                 menuiteminfo.cch = (UINT)min(_tcslen(menuiteminfo.dwTypeData), UINT_MAX);\r
2311 \r
2312                 InsertMenuItem((topmenu & MENUIGNORE) ? hMenu : subMenu, (topmenu & MENUIGNORE) ? indexMenu++ : indexSubMenu++, TRUE, &menuiteminfo);\r
2313                 if (itemStates & ITEMIS_IGNORED)\r
2314                 {\r
2315                         myIDMap[idCmd - idCmdFirst] = ShellMenuUnIgnoreSub;\r
2316                         myIDMap[idCmd++] = ShellMenuUnIgnoreSub;\r
2317                 }\r
2318                 else\r
2319                 {\r
2320                         myIDMap[idCmd - idCmdFirst] = ShellMenuIgnoreSub;\r
2321                         myIDMap[idCmd++] = ShellMenuIgnoreSub;\r
2322                 }\r
2323         }\r
2324 }\r
2325 \r
2326 HBITMAP CShellExt::IconToBitmapPARGB32(UINT uIcon)\r
2327 {\r
2328         std::map<UINT, HBITMAP>::iterator bitmap_it = bitmaps.lower_bound(uIcon);\r
2329         if (bitmap_it != bitmaps.end() && bitmap_it->first == uIcon)\r
2330                 return bitmap_it->second;\r
2331 \r
2332         HICON hIcon = (HICON)LoadImage(g_hResInst, MAKEINTRESOURCE(uIcon), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);\r
2333         if (!hIcon)\r
2334                 return NULL;\r
2335 \r
2336         if (pfnBeginBufferedPaint == NULL || pfnEndBufferedPaint == NULL || pfnGetBufferedPaintBits == NULL)\r
2337                 return NULL;\r
2338 \r
2339         SIZE sizIcon;\r
2340         sizIcon.cx = GetSystemMetrics(SM_CXSMICON);\r
2341         sizIcon.cy = GetSystemMetrics(SM_CYSMICON);\r
2342 \r
2343         RECT rcIcon;\r
2344         SetRect(&rcIcon, 0, 0, sizIcon.cx, sizIcon.cy);\r
2345         HBITMAP hBmp = NULL;\r
2346 \r
2347         HDC hdcDest = CreateCompatibleDC(NULL);\r
2348         if (hdcDest)\r
2349         {\r
2350                 if (SUCCEEDED(Create32BitHBITMAP(hdcDest, &sizIcon, NULL, &hBmp)))\r
2351                 {\r
2352                         HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcDest, hBmp);\r
2353                         if (hbmpOld)\r
2354                         {\r
2355                                 BLENDFUNCTION bfAlpha = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };\r
2356                                 BP_PAINTPARAMS paintParams = {0};\r
2357                                 paintParams.cbSize = sizeof(paintParams);\r
2358                                 paintParams.dwFlags = BPPF_ERASE;\r
2359                                 paintParams.pBlendFunction = &bfAlpha;\r
2360 \r
2361                                 HDC hdcBuffer;\r
2362                                 HPAINTBUFFER hPaintBuffer = pfnBeginBufferedPaint(hdcDest, &rcIcon, BPBF_DIB, &paintParams, &hdcBuffer);\r
2363                                 if (hPaintBuffer)\r
2364                                 {\r
2365                                         if (DrawIconEx(hdcBuffer, 0, 0, hIcon, sizIcon.cx, sizIcon.cy, 0, NULL, DI_NORMAL))\r
2366                                         {\r
2367                                                 // If icon did not have an alpha channel we need to convert buffer to PARGB\r
2368                                                 ConvertBufferToPARGB32(hPaintBuffer, hdcDest, hIcon, sizIcon);\r
2369                                         }\r
2370 \r
2371                                         // This will write the buffer contents to the destination bitmap\r
2372                                         pfnEndBufferedPaint(hPaintBuffer, TRUE);\r
2373                                 }\r
2374 \r
2375                                 SelectObject(hdcDest, hbmpOld);\r
2376                         }\r
2377                 }\r
2378 \r
2379                 DeleteDC(hdcDest);\r
2380         }\r
2381 \r
2382         DestroyIcon(hIcon);\r
2383 \r
2384         if(hBmp)\r
2385                 bitmaps.insert(bitmap_it, std::make_pair(uIcon, hBmp));\r
2386         return hBmp;\r
2387 }\r
2388 \r
2389 HRESULT CShellExt::Create32BitHBITMAP(HDC hdc, const SIZE *psize, __deref_opt_out void **ppvBits, __out HBITMAP* phBmp)\r
2390 {\r
2391         *phBmp = NULL;\r
2392 \r
2393         BITMAPINFO bmi;\r
2394         ZeroMemory(&bmi, sizeof(bmi));\r
2395         bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\r
2396         bmi.bmiHeader.biPlanes = 1;\r
2397         bmi.bmiHeader.biCompression = BI_RGB;\r
2398 \r
2399         bmi.bmiHeader.biWidth = psize->cx;\r
2400         bmi.bmiHeader.biHeight = psize->cy;\r
2401         bmi.bmiHeader.biBitCount = 32;\r
2402 \r
2403         HDC hdcUsed = hdc ? hdc : GetDC(NULL);\r
2404         if (hdcUsed)\r
2405         {\r
2406                 *phBmp = CreateDIBSection(hdcUsed, &bmi, DIB_RGB_COLORS, ppvBits, NULL, 0);\r
2407                 if (hdc != hdcUsed)\r
2408                 {\r
2409                         ReleaseDC(NULL, hdcUsed);\r
2410                 }\r