OSDN Git Service

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