OSDN Git Service

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