OSDN Git Service

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