Kiln » TortoiseHg » TortoiseHg
Clone URL:  
Pushed to one repository · View In Graph Contained in 0.8, 0.8.1, and 0.8.2

tortoise: add C++ cmenu and overlay icon shellext prototype

Changeset c3caaf07dbcc

Parent 98b4ee7b4057

by TK Soh

Changes to 22 files · Browse files at c3caaf07dbcc Showing diff from parent 98b4ee7b4057 Diff from another changeset...

Change 1 of 1 Show Entire File tortoise/​shellext/​ContextMenu.cpp Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
@@ -0,0 +1,334 @@
+#include "stdafx.h" +#include "ShellExt.h" +#include "TortoiseUtils.h" + +#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember)) +typedef STDMETHODIMP (CShellExt::*MenuAction) + (HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, + int iShowCmd); + +typedef struct { + std::string name; + std::string menuText; + std::string helpText; + std::string iconName; + MenuAction action; + int idCmd; + ULONG flags; +} MenuDescription; + +typedef std::map<std::string, MenuDescription> MenuDescriptionMap; +typedef std::map<int, MenuDescription> MenuIdCmdMap; + + +MenuDescription menuDescList[] = { + {"commit", "HG Commit...", "Commit changes in repository", + "menucommit.ico", &CShellExt::CM_Commit, 0, 0}, + {"status", "View File Status", "Repository status & changes", + "menushowchanged.ico", &CShellExt::CM_Status, 0, 0}, + {"log", "View Changelog", "View change history in repository", + "menulog.ico", &CShellExt::CM_Log, 0, 0}, + {"synch", "Synchronize", "Synchronize with remote repository", + "menusynch.ico", &CShellExt::CM_Synch, 0, 0}, + {"serve", "Web Server", "Start web server for this repository", + "proxy.ico", &CShellExt::CM_Serve, 0, 0}, + {"update", "Update To Revision", "Update working directory", + "menucheckout.ico", &CShellExt::CM_Update, 0, 0}, + {"recover", "Recovery...", "General repair and recovery of repositor", + "general.ico", &CShellExt::CM_Recover, 0, 0}, + {"userconf", "Global Settings", "Configure user wide settings", + "settings_user.ico", &CShellExt::CM_Userconf, 0, 0}, + {"repoconf", "Repository Settings", "Configure settings local to this repository", + "settings_repo.ico", &CShellExt::CM_Repoconf, 0, 0}, + {"about", "About...", "Show About Dialog", + "menuabout.ico", &CShellExt::CM_About, 0, 0}, + + // template + {"", "", "", + ".ico", NULL, 0, 0}, +}; + +MenuDescriptionMap MenuDescMap; +MenuIdCmdMap MenuIdMap; + +extern HMENU hSubMenu; +extern HINSTANCE g_hmodThisDll; + +void AddMenuList(int idCmd, std::string name) +{ + TDEBUG_TRACE("AddMenuList: idCmd = " << idCmd << " name = " << name); + MenuIdMap[idCmd] = MenuDescMap[name]; +} + +void InitMenuMaps() +{ + if (MenuDescMap.empty()) + { + int sz = sizeof(menuDescList) / sizeof(MenuDescription); + for (int i=0; i < sz; i++) + { + MenuDescription md = menuDescList[i]; + TDEBUG_TRACE("InitMenuMaps: adding " << md.name); + MenuDescMap[md.name] = md; + } + } + + MenuIdMap.clear(); +} + +void InsertMenuItemWithIcon(HMENU hMenu, int indexMenu, int idCmd, + std::string menuText, std::string iconName) +{ + MENUITEMINFO mi; + mi.cbSize = sizeof(mi); + mi.dwTypeData = const_cast<char*> (menuText.c_str()); + mi.cch = static_cast<UINT> (menuText.length()); + mi.wID = idCmd; + mi.fType = MFT_STRING; + + HICON h = GetTortoiseIcon(iconName); + if (h) + { + mi.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_BITMAP | MIIM_DATA; + mi.dwItemData = (ULONG_PTR) h; + mi.hbmpItem = HBMMENU_CALLBACK; + } + else + { + TDEBUG_TRACE(" InsertMenuItemWithIcon: can't find " + iconName); + mi.fMask = MIIM_TYPE | MIIM_ID; + } + InsertMenuItem(hMenu, indexMenu, TRUE, &mi); +} + +void InsertSubMenuItemWithIcon(HMENU hMenu, HMENU hSubMenu, int indexMenu, int idCmd, + std::string menuText, std::string iconName) +{ + MENUITEMINFO mi; + mi.cbSize = sizeof(mi); + mi.fMask = MIIM_SUBMENU | MIIM_STRING | MIIM_ID; + mi.fType = MFT_STRING; + mi.dwTypeData = const_cast<char*> (menuText.c_str()); + mi.cch = static_cast<UINT> (menuText.length()); + mi.wID = idCmd; + mi.hSubMenu = hSubMenu; + HICON h = GetTortoiseIcon(iconName); + if (h) + { + mi.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_SUBMENU | MIIM_ID | + MIIM_BITMAP | MIIM_DATA; + mi.dwItemData = (ULONG_PTR) h; + mi.hbmpItem = HBMMENU_CALLBACK; + } + else + { + TDEBUG_TRACE(" InsertSubMenuItemWithIcon: can't find " + iconName); + } + InsertMenuItem(hMenu, indexMenu, TRUE, &mi); +} + +void InsertMenuItemByName(HMENU hMenu, std::string name, int indexMenu, + int idCmd, int idCmdFirst) +{ + TDEBUG_TRACE("InsertMenuItemByName: name = " << name); + MenuDescriptionMap::iterator iter = MenuDescMap.find(name); + if (iter == MenuDescMap.end()) + { + TDEBUG_TRACE("InsertMenuItemByName: can't find menu info for " << name); + return; + } + + MenuDescription md = MenuDescMap[name]; + AddMenuList(idCmd - idCmdFirst, name); + InsertMenuItemWithIcon(hMenu, indexMenu, idCmd, md.menuText, md.iconName); +} + +// IContextMenu +STDMETHODIMP +CShellExt::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, + UINT idCmdLast, UINT uFlags) +{ + TDEBUG_TRACE("CShellExt::QueryContextMenu"); + InitMenuMaps(); + + UINT idCmd = idCmdFirst; + BOOL bAppendItems = TRUE; + + if((uFlags & 0x000F) == CMF_NORMAL) + bAppendItems = TRUE; + else if (uFlags & CMF_VERBSONLY) + bAppendItems = TRUE; + else if (uFlags & CMF_EXPLORE) + bAppendItems = TRUE; + else + bAppendItems = FALSE; + + if (!bAppendItems) + return NOERROR; + + // check if target directory is a Mercurial repository + bool isHgrepo = false; + std::string cwd; + if (!myFolder.empty()) + { + cwd = myFolder; + } + else if (!myFiles.empty()) + { + cwd = IsDirectory(myFiles[0])? myFiles[0] : DirName(myFiles[0]); + } + if (!cwd.empty()) + isHgrepo = IsHgRepo(cwd); + + // start building TortoiseHg menus and submenus + InsertMenu(hMenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, 0, NULL); + indexMenu++; + + if (isHgrepo) + InsertMenuItemByName(hMenu, "commit", indexMenu++, idCmd++, idCmdFirst); + + TDEBUG_TRACE(" CShellExt::QueryContextMenu: adding sub menus"); + HMENU hSubMenu = CreatePopupMenu(); + int indexSubMenu = 0; + if(hSubMenu) + { + if (isHgrepo) + { + InsertMenuItemByName(hSubMenu, "status", indexSubMenu++, idCmd++, idCmdFirst); + + InsertMenu(hSubMenu, indexSubMenu++, MF_SEPARATOR | MF_BYPOSITION, + 0, NULL); + InsertMenuItemByName(hSubMenu, "log", indexSubMenu++, idCmd++, idCmdFirst); + + InsertMenu(hSubMenu, indexSubMenu++, MF_SEPARATOR | MF_BYPOSITION, + 0, NULL); + InsertMenuItemByName(hSubMenu, "update", indexSubMenu++, idCmd++, idCmdFirst); + + InsertMenu(hSubMenu, indexSubMenu++, MF_SEPARATOR | MF_BYPOSITION, + 0, NULL); + InsertMenuItemByName(hSubMenu, "synch", indexSubMenu++, idCmd++, idCmdFirst); + InsertMenuItemByName(hSubMenu, "recover", indexSubMenu++, idCmd++, idCmdFirst); + InsertMenuItemByName(hSubMenu, "serve", indexSubMenu++, idCmd++, idCmdFirst); + + InsertMenu(hSubMenu, indexSubMenu++, MF_SEPARATOR | MF_BYPOSITION, + 0, NULL); + InsertMenuItemByName(hSubMenu, "userconf", indexSubMenu++, idCmd++, idCmdFirst); + } + + InsertMenuItemByName(hSubMenu, "repoconf", indexSubMenu++, idCmd++, idCmdFirst); + + InsertMenu(hSubMenu, indexSubMenu++, MF_SEPARATOR | MF_BYPOSITION, + 0, NULL); + + InsertMenuItemByName(hSubMenu, "about", indexSubMenu++, idCmd++, idCmdFirst); + } + + TDEBUG_TRACE(" CShellExt::QueryContextMenu: adding main THG menu"); + InsertSubMenuItemWithIcon(hMenu, hSubMenu, indexMenu++, idCmd++, + "TortoiseHG...", "hg.ico"); + + InsertMenu(hMenu, indexMenu++, MF_SEPARATOR | MF_BYPOSITION, 0, NULL); + + return ResultFromShort(idCmd - idCmdFirst); +} + +STDMETHODIMP +CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) +{ + TDEBUG_TRACE("CShellExt::InvokeCommand"); + + HRESULT hr = E_INVALIDARG; + if (!HIWORD(lpcmi->lpVerb)) + { + UINT idCmd = LOWORD(lpcmi->lpVerb); + TDEBUG_TRACE("CShellExt::InvokeCommand: idCmd = " << idCmd); + MenuIdCmdMap::iterator iter = MenuIdMap.find(idCmd); + if(iter != MenuIdMap.end()) + { + MenuAction action = MenuIdMap[idCmd].action; + hr = CALL_MEMBER_FN(*this, action)(lpcmi->hwnd, lpcmi->lpDirectory, + lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow); + } + else + { + TDEBUG_TRACE("CShellExt::InvokeCommand: action not found for idCmd " << idCmd); + } + } + return hr; +} + +STDMETHODIMP +CShellExt::GetCommandString(UINT idCmd, UINT uFlags, UINT FAR *reserved, + LPSTR pszName, UINT cchMax) +{ + TDEBUG_TRACE("CShellExt::GetCommandString"); + + *pszName = 0; + char *psz; + + TDEBUG_TRACE("CShellExt::GetCommandString: idCmd = " << idCmd); + MenuIdCmdMap::iterator iter = MenuIdMap.find(idCmd); + if (iter != MenuIdMap.end()) + { + TDEBUG_TRACE("CShellExt::GetCommandString: name = " << MenuIdMap[idCmd].name); + psz = (char*)MenuIdMap[idCmd].helpText.c_str(); + } + else + { + TDEBUG_TRACE("CShellExt::GetCommandString: can't find idCmd " << idCmd); + psz = ""; + } + + wcscpy((wchar_t*)pszName, _WCSTR(psz)); + return NOERROR; +} + +STDMETHODIMP CShellExt::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LRESULT res; + return HandleMenuMsg2(uMsg, wParam, lParam, &res); +} + +STDMETHODIMP CShellExt::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult) +{ + TDEBUG_ENTER("CShellExt::HandleMenuMsg2"); + // A great tutorial on owner drawn menus in shell extension can be found + // here: http://www.codeproject.com/shell/shellextguide7.asp + + LRESULT res; + if (!pResult) + pResult = &res; + *pResult = FALSE; + + switch (uMsg) + { + case WM_MEASUREITEM: + { + MEASUREITEMSTRUCT* lpmis = (MEASUREITEMSTRUCT*)lParam; + if (lpmis==NULL) + break; + lpmis->itemWidth += 2; + if(lpmis->itemHeight < 16) + lpmis->itemHeight = 16; + *pResult = TRUE; + } + break; + case WM_DRAWITEM: + { + DRAWITEMSTRUCT* lpdis = (DRAWITEMSTRUCT*)lParam; + if (!lpdis || (lpdis->CtlType != ODT_MENU) || !lpdis->itemData) + break; //not for a menu + DrawIconEx(lpdis->hDC, + lpdis->rcItem.left - 16, + lpdis->rcItem.top + (lpdis->rcItem.bottom - lpdis->rcItem.top - 16) / 2, + (HICON) lpdis->itemData, 16, 16, + 0, 0, DI_NORMAL); + *pResult = TRUE; + } + break; + default: + return NOERROR; + } + + return NOERROR; +}
Change 1 of 1 Show Entire File tortoise/​shellext/​FixWinDefs.h Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@@ -0,0 +1,32 @@
+// TortoiseCVS - a Windows shell extension for easy version control + +// Copyright (C) 2003 - Hartmut Honisch +// <Hartmut_Honisch@web.de> - November 2003 + +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#ifndef FIX_WIN_DEFS_H +#define FIX_WIN_DEFS_H + +#undef SetPort +#undef FindWindow +#undef CreateDialog +#undef GetCharWidth +#undef GetWindowStyle +#undef IsMaximized +#undef GetUsername +#undef min +#undef max + +#endif /* FIX_WIN_DEFS_H */
Change 1 of 1 Show Entire File tortoise/​shellext/​IconOverlay.cpp Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
@@ -0,0 +1,78 @@
+#include "stdafx.h" +#include "ShellExt.h" +#include "TortoiseUtils.h" +#include "StringUtils.h" +#include "PipeUtils.h" + +STDMETHODIMP CShellExt::GetOverlayInfo(LPWSTR pwszIconFile, int cchMax, + int *pIndex, DWORD *pdwFlags) +{ + *pIndex = 0; + *pdwFlags = ISIOI_ICONFILE; + + // get installation path + std::string dir = GetTHgProgRoot(); + if (dir.empty()) + { + TDEBUG_TRACE("GetOverlayInfo: THG root is empty"); + wcsncpy(pwszIconFile, L"", cchMax); + return S_OK; + } + + // find icon per overlay type + std::wstring dirWide = MultibyteToWide(dir); + wcsncpy(pwszIconFile, dirWide.c_str(), cchMax); + cchMax -= static_cast<int>(dirWide.size()) + 1; +/* + switch (myTortoiseClass) + { + case TORTOISE_OLE_ADDED: + wcsncat(pwszIconFile, L"\\icons\\status\\added.ico", cchMax); + break; + case TORTOISE_OLE_MODIFIED: + wcsncat(pwszIconFile, L"\\icons\\status\\changed.ico", cchMax); + break; + case TORTOISE_OLE_UNCHANGED: + wcsncat(pwszIconFile, L"\\icons\\status\\unchanged.ico", cchMax); + break; + default: + break; + } +*/ + std::string path = WideToMultibyte(pwszIconFile); + TDEBUG_TRACE("GetOverlayInfo: icon path = " << path); + + return S_OK; +} + +STDMETHODIMP CShellExt::GetPriority(int *pPriority) +{ + *pPriority = 1; + return S_OK; +} + +#define BUFSIZE 512 + +STDMETHODIMP CShellExt::IsMemberOf(LPCWSTR pwszPath, DWORD /* dwAttrib */) +{ + TCHAR status[BUFSIZE] = TEXT(""); + int bufsize = BUFSIZE * sizeof(TCHAR); + std::string mbstr = WideToMultibyte(pwszPath); + + TDEBUG_TRACE("IsMemberOf: search for " << mbstr.c_str()); + int cbRead = query_pipe(mbstr.c_str(), status, bufsize); + + if (cbRead < 0) + return S_FALSE; + else if (myTortoiseClass == TORTOISE_OLE_ADDED && + strcmp(status, "added") == 0) + return S_OK; + else if (myTortoiseClass == TORTOISE_OLE_MODIFIED && + strcmp(status, "modified") == 0) + return S_OK; + else if (myTortoiseClass == TORTOISE_OLE_UNCHANGED && + strcmp(status, "unchanged") == 0) + return S_OK; + + return S_FALSE; +}
Change 1 of 1 Show Entire File tortoise/​shellext/​Makefile Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@@ -0,0 +1,33 @@
+DLLNAME=THgShell.dll + +OBJECTS = ContextMenu.o \ + IconOverlay.o \ + MenuActions.o \ + ShellExt.o \ + TortoiseUtils.o \ + PipeUtils.o \ + ShellUtils2.o \ + StringUtils.o + +DEFFILE=ShellExt.def + +LDFLAGS=-L/lib -lole32 -lkernel32 -luser32 -lgdi32 -lshlwapi \ + -lwininet -lwinmm -luuid \ + -Wl,--subsystem,windows,--enable-stdcall-fixup,$(DEFFILE) \ + -mwindows -shared + +# set DEBUG env var to 1 to enable debug trace +ifeq ($(DEBUG),1) +CXXFLAGS+=-D_DEBUG +endif + +all: PipeUtils $(DLLNAME) + +$(DLLNAME): $(OBJECTS) + g++ -o $@ $(OBJECTS) $(LDFLAGS) + +PipeUtils: PipeUtils.cpp PipeUtils.h StringUtils.o TortoiseUtils.o + g++ -o $@ $(CXXFLAGS) -DAPPMAIN $< StringUtils.o TortoiseUtils.o + +clean: + rm -f *.o *.dll *.exe
Change 1 of 1 Show Entire File tortoise/​shellext/​MenuActions.cpp Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
@@ -0,0 +1,149 @@
+#include "stdafx.h" +#include "ShellExt.h" +#include "TortoiseUtils.h" +#include "StringUtils.h" + +#include <stdio.h> +#include <vector> + +void CShellExt::DoHgProc(const std::string &cmd, bool nofiles, bool nogui) +{ + std::string dir = GetTHgProgRoot(); + TDEBUG_TRACE("DoHgProc: THG root = " << dir); + if (dir.empty()) + { + TDEBUG_TRACE("DoHgProc: THG root is empty"); + return; + } + std::string hgcmd = Quote(dir + "\\hgproc.bat") + " --command " + cmd; + + if (nogui) + hgcmd += " --nogui"; + + std::string cwd; + std::vector<std::string> filelist; + if (!myFolder.empty()) + { + cwd = myFolder; + filelist.push_back(GetHgRepoRoot(myFolder)); + } + else if (!myFiles.empty()) + { + cwd = IsDirectory(myFiles[0])? myFiles[0] : DirName(myFiles[0]); + filelist = myFiles; + } + else + { + TDEBUG_TRACE("DoHgProc: can't get cwd"); + return; + } + + hgcmd += " --cwd " + Quote(cwd); + hgcmd += " --root " + Quote(GetHgRepoRoot(cwd)); + + if (!nofiles) + { + std::string tempfile = GetTemporaryFile(); + SECURITY_ATTRIBUTES sa; + memset(&sa, 0, sizeof(sa)); + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + + TDEBUG_TRACE("DoHgProc: temp file = " << tempfile); + HANDLE tempfileHandle = CreateFileA(tempfile.c_str(), GENERIC_WRITE, + FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + + for (int i=0; i<filelist.size(); i++) + { + DWORD dwWritten; + TDEBUG_TRACE("DoHgProc: temp file adding " << filelist[i]); + WriteFile(tempfileHandle, filelist[i].c_str(), + static_cast<DWORD>(filelist[i].size()), &dwWritten, 0); + } + CloseHandle(tempfileHandle); + hgcmd += " --listfile " + Quote(tempfile); + hgcmd += " --deletelistfile" ; + } + + LaunchCommand(hgcmd); +} + +STDMETHODIMP +CShellExt::CM_Commit(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, + LPCSTR pszParam, int iShowCmd) +{ + DoHgProc("commit"); + return NOERROR; +} + +STDMETHODIMP +CShellExt::CM_Status(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, + LPCSTR pszParam, int iShowCmd) +{ + DoHgProc("status"); + return NOERROR; +} + +STDMETHODIMP +CShellExt::CM_Log(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, + LPCSTR pszParam, int iShowCmd) +{ + DoHgProc("log"); + return NOERROR; +} + +STDMETHODIMP +CShellExt::CM_About(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, + LPCSTR pszParam, int iShowCmd) +{ + DoHgProc("about"); + return NOERROR; +} + +STDMETHODIMP +CShellExt::CM_Synch(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, + LPCSTR pszParam, int iShowCmd) +{ + DoHgProc("synch"); + return NOERROR; +} + +STDMETHODIMP +CShellExt::CM_Serve(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, + LPCSTR pszParam, int iShowCmd) +{ + DoHgProc("serve"); + return NOERROR; +} + +STDMETHODIMP +CShellExt::CM_Update(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, + LPCSTR pszParam, int iShowCmd) +{ + DoHgProc("update"); + return NOERROR; +} + +STDMETHODIMP +CShellExt::CM_Recover(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, + LPCSTR pszParam, int iShowCmd) +{ + DoHgProc("recovery"); + return NOERROR; +} + +STDMETHODIMP +CShellExt::CM_Userconf(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, + LPCSTR pszParam, int iShowCmd) +{ + DoHgProc("config", true); + return NOERROR; +} + +STDMETHODIMP +CShellExt::CM_Repoconf(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, + LPCSTR pszParam, int iShowCmd) +{ + DoHgProc("config"); + return NOERROR; +}
Change 1 of 1 Show Entire File tortoise/​shellext/​PipeUtils.cpp Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
@@ -0,0 +1,95 @@
+#include "stdafx.h" +#include "PipeUtils.h" +#include "StringUtils.h" +#include "TortoiseUtils.h" +#include <stdio.h> +#include <conio.h> +#include <tchar.h> +#include <wchar.h> + +LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\PyPipeService"); + +#define BUFSIZE 512 + +int query_pipe(LPCSTR cstr, TCHAR *chReadBuf, int bufsize) +{ + BOOL fSuccess; + DWORD cbRead; + + int outlen = (lstrlen((TCHAR*)cstr))*sizeof(TCHAR); + TDEBUG_TRACE("sending " << outlen << " bytes to pipe: " << cstr); + + fSuccess = CallNamedPipe( + lpszPipename, // pipe name + (void *)cstr, // message to server + outlen, // message length + chReadBuf, // buffer to receive reply + bufsize, // size of read buffer + &cbRead, // number of bytes read + NMPWAIT_NOWAIT); // waits for 0 seconds + + if (fSuccess || GetLastError() == ERROR_MORE_DATA) + { + TDEBUG_TRACE("receive " << cbRead << " bytes from pipe: " << chReadBuf); + return cbRead; + } + else + { + return -1; + } +} + +int _test_pipe(LPCSTR lpszWrite) +{ + TCHAR readBuf[BUFSIZE] = TEXT(""); + int bufsize = BUFSIZE*sizeof(TCHAR); + int cbRead = query_pipe(lpszWrite, readBuf, bufsize); + + if (cbRead >= 0) + { + _tprintf( TEXT("read: %s\n"), readBuf ); + } + else + { + _tprintf( TEXT("error calling pipe\n") ); + } +} + +#ifdef APPMAIN +int _tmain(int argc, TCHAR *argv[]) +{ + LPTSTR lpszWrite = TEXT(""); + + if (argc < 2) + { + _tprintf(TEXT("usage: %s file1 file2 ...\n"), argv[0]); + return 1; + } + + for (int i=1; i<argc; i++) + { + lpszWrite = argv[i]; + _test_pipe(lpszWrite); + } + WCHAR file[] = L"C:\\hg\\hg-tortoise\\hgproc.py"; + std::string mbstr = WideToMultibyte(file); + const char *cstr = mbstr.c_str(); + _test_pipe(cstr); + + std::string root = GetTHgProgRoot(); + if (root != "") + { + _tprintf(TEXT("THG root = %s\n"), root.c_str() ); + } + else + { + _tprintf(TEXT("THG root not found in registry\n")); + } + + //LaunchCommand("notepad"); + //LaunchCommand("D:\\Profiles\\r28629\\My Documents\\Mercurial\\repos\\hg-tortoise-dev\\dist\\hgproc.exe") + //LaunchCommand("\"D:\\Profiles\\r28629\\My Documents\\Mercurial\\repos\\hg-tortoise-namedpipe\\hgproc.bat\""); + + return 0; +} +#endif
Change 1 of 1 Show Entire File tortoise/​shellext/​PipeUtils.h Stacked
 
 
 
 
 
 
 
 
1
2
3
4
5
6
@@ -0,0 +1,6 @@
+#ifndef __NTServiceManager_PipeUtils_Defined__ +#define __NTServiceManager_PipeUtils_Defined__ + +int query_pipe(LPCSTR lpszWrite, TCHAR *chReadBuf, int bufsize); + +#endif
Change 1 of 1 Show Entire File tortoise/​shellext/​Registry.cpp Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
@@ -0,0 +1,799 @@
+ + +//#include "stdafx.h" +#include <windows.h> +#include <winreg.h> +#include "Registry.h" + +#define CLASS_NAME_LENGTH 255 + +/* IMPORTANT NOTES ABOUT CREGISTRY: + + CRegistry never keeps a key open past the end of a function call. + This is incase the application crashes before the next call to close + the registry + + INCLUDE FILES + "winreg.h" and "afxdisp.h" must be included in "stdafx.h" + + KEY NAMES: + Key names must not begin with a \ and only absolute strings are accepted + +*/ + + + +CRegistry::CRegistry() +{ + m_hRootKey = HKEY_CURRENT_USER; + m_bLazyWrite = TRUE; + m_nLastError = ERROR_SUCCESS; +} + +CRegistry::~CRegistry() +{ + ClearKey(); +} + + +BOOL CRegistry::ClearKey() +{ + /* Call CloseKey to write the current key to the registry and close the + key. An application should not keep keys open any longer than necessary. + Calling CloseKey when there is no current key has no effect.*/ + + m_strCurrentPath.Empty(); + m_hRootKey = HKEY_CURRENT_USER; + m_bLazyWrite = TRUE; + return TRUE; +} + + + +BOOL CRegistry::SetRootKey(HKEY hRootKey) +{ + // sets the root key + // make sure to set it to a valid key + if (hRootKey != HKEY_CLASSES_ROOT && + hRootKey != HKEY_CURRENT_USER && + hRootKey != HKEY_LOCAL_MACHINE && + hRootKey != HKEY_USERS) return FALSE; + + m_hRootKey = hRootKey; + return TRUE; +} + + +BOOL CRegistry::CreateKey(CString strKey) +{ + /* Use CreateKey to add a new key to the registry. + Key is the name of the key to create. Key must be + an absolute name. An absolute key + begins with a backslash (\) and is a subkey of + the root key. */ + + ASSERT(strKey[0] != '\\'); + HKEY hKey; + + DWORD dwDisposition = 0; + + if (::RegCreateKeyEx(m_hRootKey, LPCTSTR(strKey), 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, + &dwDisposition) != ERROR_SUCCESS) return FALSE; + + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + m_strCurrentPath = strKey; + return TRUE; +} + + +BOOL CRegistry::DeleteKey(CString strKey) +{ + /* Call DeleteKey to remove a specified key and its associated data, + if any, from the registry. Returns FALSE is there are subkeys + Subkeys must be explicitly deleted by separate calls to DeleteKey. + DeleteKey returns True if key deletion is successful. On error, + DeleteKey returns False. */ + + // need to open the key first with RegOpenKeyEx + ASSERT(FALSE); // not yet implemented + ASSERT(strKey[0] != '\\'); + + if (!KeyExists(strKey)) return TRUE; + if (::RegDeleteKey(m_hRootKey, strKey) != ERROR_SUCCESS) return FALSE; + return TRUE; +} + + + +BOOL CRegistry::DeleteValue(CString strName) +{ + /* Call DeleteValue to remove a specific data value + associated with the current key. Name is string + containing the name of the value to delete. Keys can contain + multiple data values, and every value associated with a key + has a unique name. */ + + ASSERT(m_strCurrentPath.GetLength() > 0); + HKEY hKey; + LONG lResult; + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_SET_VALUE, &hKey) != ERROR_SUCCESS) return FALSE; + + lResult = ::RegDeleteValue(hKey, LPCTSTR(strName)); + ::RegCloseKey(hKey); + + if (lResult == ERROR_SUCCESS) return TRUE; + return FALSE; +} + + +int CRegistry::GetDataSize(CString strValueName) +{ + /* Call GetDataSize to determine the size, in bytes, of + a data value associated with the current key. ValueName + is a string containing the name of the data value to query. + On success, GetDataSize returns the size of the data value. + On failure, GetDataSize returns -1. */ + + HKEY hKey; + ASSERT(m_strCurrentPath.GetLength() > 0); + LONG lResult; + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) return -1; + + DWORD dwSize = 1; + lResult = ::RegQueryValueEx(hKey, LPCTSTR(strValueName), + NULL, NULL, NULL, &dwSize); + ::RegCloseKey(hKey); + + if (lResult != ERROR_SUCCESS) return -1; + return (int)dwSize; +} + +DWORD CRegistry::GetDataType(CString strValueName) +{ + HKEY hKey; + ASSERT(m_strCurrentPath.GetLength() > 0); + + m_nLastError = ::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_QUERY_VALUE, &hKey); + + if (m_nLastError != ERROR_SUCCESS) return 0; + + DWORD dwType = 1; + m_nLastError = ::RegQueryValueEx(hKey, LPCTSTR(strValueName), + NULL, &dwType, NULL, NULL); + ::RegCloseKey(hKey); + + if (m_nLastError == ERROR_SUCCESS) return dwType; + + return 0; +} + + + +int CRegistry::GetSubKeyCount() +{ + /* Call this function to determine the number of subkeys. + the function returns -1 on error */ + HKEY hKey; + ASSERT(m_strCurrentPath.GetLength() > 0); + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS) return -1; + + LONG lResult; + DWORD dwSubKeyCount, dwValueCount, dwClassNameLength, + dwMaxSubKeyName, dwMaxValueName, dwMaxValueLength; + FILETIME ftLastWritten; + + _TCHAR szClassBuffer[CLASS_NAME_LENGTH]; + + dwClassNameLength = CLASS_NAME_LENGTH; + lResult = ::RegQueryInfoKey(hKey, szClassBuffer, &dwClassNameLength, + NULL, &dwSubKeyCount, &dwMaxSubKeyName, NULL, &dwValueCount, + &dwMaxValueName, &dwMaxValueLength, NULL, &ftLastWritten); + + ::RegCloseKey(hKey); + if (lResult != ERROR_SUCCESS) return -1; + + return (int)dwSubKeyCount; +} + + +int CRegistry::GetValueCount() +{ + /* Call this function to determine the number of subkeys. + the function returns -1 on error */ + HKEY hKey; + ASSERT(m_strCurrentPath.GetLength() > 0); + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS) return -1; + + LONG lResult; + DWORD dwSubKeyCount, dwValueCount, dwClassNameLength, + dwMaxSubKeyName, dwMaxValueName, dwMaxValueLength; + FILETIME ftLastWritten; + + _TCHAR szClassBuffer[CLASS_NAME_LENGTH]; + + dwClassNameLength = CLASS_NAME_LENGTH; + lResult = ::RegQueryInfoKey(hKey, szClassBuffer, &dwClassNameLength, + NULL, &dwSubKeyCount, &dwMaxSubKeyName, NULL, &dwValueCount, + &dwMaxValueName, &dwMaxValueLength, NULL, &ftLastWritten); + + ::RegCloseKey(hKey); + if (lResult != ERROR_SUCCESS) return -1; + + return (int)dwValueCount; +} + + +BOOL CRegistry::KeyExists(CString strKey, HKEY hRootKey) +{ + /* Call KeyExists to determine if a key of a specified name exists. + Key is the name of the key for which to search. */ + + ASSERT(strKey[0] != '\\'); + HKEY hKey; + + if (hRootKey == NULL) hRootKey = m_hRootKey; + + LONG lResult = ::RegOpenKeyEx(hRootKey, LPCTSTR(strKey), 0, + KEY_ALL_ACCESS, &hKey); + ::RegCloseKey(hKey); + if (lResult == ERROR_SUCCESS) return TRUE; + return FALSE; +} + +BOOL CRegistry::SetKey(CString strKey, BOOL bCanCreate) +{ + /* Call SetKey to make a specified key the current key. Key is the + name of the key to open. If Key is null, the CurrentKey property + is set to the key specified by the RootKey property. + + CanCreate specifies whether to create the specified key if it does + not exist. If CanCreate is True, the key is created if necessary. + + Key is opened or created with the security access value KEY_ALL_ACCESS. + OpenKey only creates non-volatile keys, A non-volatile key is stored in + the registry and is preserved when the system is restarted. + + OpenKey returns True if the key is successfully opened or created */ + + ASSERT(strKey[0] != '\\'); + HKEY hKey; + + + // close the current key if it is open + if (strKey.GetLength() == 0) + { + m_strCurrentPath.Empty(); + return TRUE; + } + + DWORD dwDisposition; + if (bCanCreate) // open the key with RegCreateKeyEx + { + if (::RegCreateKeyEx(m_hRootKey, LPCTSTR(strKey), 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, + &dwDisposition) != ERROR_SUCCESS) return FALSE; + m_strCurrentPath = strKey; + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + return TRUE; + } + + // otherwise, open the key without creating + // open key requires no initial slash + m_nLastError = ::RegOpenKeyEx(m_hRootKey, LPCTSTR(strKey), 0, + KEY_ALL_ACCESS, &hKey); + if (m_nLastError != ERROR_SUCCESS) return FALSE; + m_strCurrentPath = strKey; + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + return TRUE; +} + + +BOOL CRegistry::ValueExists(CString strName) +{ + /* Call ValueExists to determine if a particular key exists in + the registry. Calling Value Exists is especially useful before + calling other TRegistry methods that operate only on existing keys. + + Name is the name of the data value for which to check. + ValueExists returns True if a match if found, False otherwise. */ + + HKEY hKey; + LONG lResult; + ASSERT(m_strCurrentPath.GetLength() > 0); + + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS) return FALSE; + + lResult = ::RegQueryValueEx(hKey, LPCTSTR(strName), NULL, + NULL, NULL, NULL); + ::RegCloseKey(hKey); + + if (lResult == ERROR_SUCCESS) return TRUE; + return FALSE; +} + + +void CRegistry::RenameValue(CString strOldName, CString strNewName) +{ + /* Call RenameValue to change the name of a data value associated + with the current key. OldName is a string containing the current + name of the data value. NewName is a string containing the replacement + name for the data value. + + If OldName is the name of an existing data value for the current key, + and NewName is not the name of an existing data value for the current + key, RenameValue changes the data value name as specified. Otherwise + the current name remains unchanged. + */ + ASSERT(FALSE); // functionality not yet implemented +} + + + + +COleDateTime CRegistry::ReadDateTime(CString strName, COleDateTime dtDefault) +{ + /* Call ReadDate to read a date value from a specified data value + associated with the current key. Name is the name of the data value to read. + If successful, ReadDate returns a Delphi TDateTime value. The integral part + of a TDateTime value is the number of days that have passed since 12/30/1899. + The fractional part of a TDateTime value is the time of day. + On error, an exception is raised, and the value returned by this function + should be discarded. */ + + DWORD dwType = REG_BINARY; + COleDateTime dt; + DWORD dwSize = sizeof(dt); + HKEY hKey; + + ASSERT(m_strCurrentPath.GetLength() > 0); + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_READ, &hKey) != ERROR_SUCCESS) return dtDefault; + if (::RegQueryValueEx(hKey, LPCTSTR(strName), NULL, + &dwType, (LPBYTE)&dt, &dwSize) != ERROR_SUCCESS) dt = dtDefault; + ::RegCloseKey(hKey); + return dt; +} + + +double CRegistry::ReadFloat(CString strName, double fDefault) +{ + /* Call ReadFloat to read a float value from a specified + data value associated with the current key. Name is the name + of the data value to read. + + If successful, ReadFloat returns a double value. + On error, an exception is raised, and the value returned by + this function should be discarded. */ + + DWORD dwType = REG_BINARY; + double d; + DWORD dwSize = sizeof(d); + HKEY hKey; + + ASSERT(m_strCurrentPath.GetLength() > 0); + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_READ, &hKey) != ERROR_SUCCESS) return fDefault; + + if (::RegQueryValueEx(hKey, LPCTSTR(strName), NULL, + &dwType, (LPBYTE)&d, &dwSize) != ERROR_SUCCESS) d = fDefault; + ::RegCloseKey(hKey); + return d; +} + +CString CRegistry::ReadString(CString strName, CString strDefault) +{ + DWORD dwType = REG_SZ; + DWORD dwSize = 255; + BOOL bSuccess = TRUE; + _TCHAR sz[255]; + HKEY hKey; + + + ASSERT(m_strCurrentPath.GetLength() > 0); + + // make sure it is the proper type + dwType = GetDataType(strName); + + if (dwType != REG_SZ && dwType != REG_EXPAND_SZ) + { + return strDefault; + } + + m_nLastError = ::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_READ, &hKey); + if (m_nLastError != ERROR_SUCCESS) return strDefault; + + m_nLastError = ::RegQueryValueEx(hKey, LPCTSTR(strName), NULL, + &dwType, (LPBYTE)sz, &dwSize); + if (m_nLastError != ERROR_SUCCESS) bSuccess = FALSE; + ::RegCloseKey(hKey); + + if (!bSuccess) return strDefault; + return CString((LPCTSTR)sz); +} + +DWORD CRegistry::ReadDword(CString strName, DWORD dwDefault) +{ + DWORD dwType = REG_DWORD; + DWORD dw; + DWORD dwSize = sizeof(dw); + HKEY hKey; + + ASSERT(m_strCurrentPath.GetLength() > 0); + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_READ, &hKey) != ERROR_SUCCESS) return dwDefault; + + if (::RegQueryValueEx(hKey, LPCTSTR(strName), NULL, + &dwType, (LPBYTE)&dw, &dwSize) != ERROR_SUCCESS) dw = dwDefault; + ::RegCloseKey(hKey); + return dw; +} + + + +int CRegistry::ReadInt(CString strName, int nDefault) +{ + DWORD dwType = REG_BINARY; + int n; + DWORD dwSize = sizeof(n); + HKEY hKey; + + ASSERT(m_strCurrentPath.GetLength() > 0); + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_READ, &hKey) != ERROR_SUCCESS) return nDefault; + + if (::RegQueryValueEx(hKey, LPCTSTR(strName), NULL, + &dwType, (LPBYTE)&n, &dwSize) != ERROR_SUCCESS) n = nDefault; + ::RegCloseKey(hKey); + return n; +} + +BOOL CRegistry::ReadBool(CString strName, BOOL bDefault) +{ + DWORD dwType = REG_BINARY; + BOOL b; + DWORD dwSize = sizeof(b); + HKEY hKey; + + ASSERT(m_strCurrentPath.GetLength() > 0); + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_READ, &hKey) != ERROR_SUCCESS) return bDefault; + + if (::RegQueryValueEx(hKey, LPCTSTR(strName), NULL, + &dwType, (LPBYTE)&b, &dwSize) != ERROR_SUCCESS) b = bDefault; + ::RegCloseKey(hKey); + return b; +} + + +COLORREF CRegistry::ReadColor(CString strName, COLORREF rgbDefault) +{ + DWORD dwType = REG_BINARY; + COLORREF rgb; + DWORD dwSize = sizeof(rgb); + HKEY hKey; + + ASSERT(m_strCurrentPath.GetLength() > 0); + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_READ, &hKey) != ERROR_SUCCESS) return rgbDefault; + + if (::RegQueryValueEx(hKey, LPCTSTR(strName), NULL, + &dwType, (LPBYTE)&rgb, &dwSize) != ERROR_SUCCESS) rgb = rgbDefault; + ::RegCloseKey(hKey); + return rgb; +} + +BOOL CRegistry::ReadFont(CString strName, CFont* pFont) +{ + DWORD dwType = REG_BINARY; + DWORD dwSize = sizeof(LOGFONT); + BOOL bSuccess = TRUE; + HKEY hKey; + LOGFONT lf; + + ASSERT(m_strCurrentPath.GetLength() > 0); + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_READ, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegQueryValueEx(hKey, LPCTSTR(strName), NULL, + &dwType, (LPBYTE)&lf, &dwSize) != ERROR_SUCCESS) bSuccess = FALSE; + ::RegCloseKey(hKey); + if (bSuccess) + { + pFont->Detach(); + pFont->CreateFontIndirect(&lf); + } + return bSuccess; +} + + +BOOL CRegistry::ReadPoint(CString strName, CPoint* pPoint) +{ + DWORD dwType = REG_BINARY; + DWORD dwSize = sizeof(CPoint); + BOOL bSuccess = TRUE; + HKEY hKey; + + ASSERT(m_strCurrentPath.GetLength() > 0); + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_READ, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegQueryValueEx(hKey, LPCTSTR(strName), NULL, + &dwType, (LPBYTE)pPoint, &dwSize) != ERROR_SUCCESS) bSuccess = FALSE; + ::RegCloseKey(hKey); + return bSuccess; +} + +BOOL CRegistry::ReadSize(CString strName, CSize* pSize) +{ + DWORD dwType = REG_BINARY; + DWORD dwSize = sizeof(CSize); + BOOL bSuccess = TRUE; + HKEY hKey; + + ASSERT(m_strCurrentPath.GetLength() > 0); + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_READ, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegQueryValueEx(hKey, LPCTSTR(strName), NULL, + &dwType, (LPBYTE)pSize, &dwSize) != ERROR_SUCCESS) bSuccess = FALSE; + ::RegCloseKey(hKey); + return bSuccess; +} + +BOOL CRegistry::ReadRect(CString strName, CRect* pRect) +{ + DWORD dwType = REG_BINARY; + DWORD dwSize = sizeof(CRect); + BOOL bSuccess = TRUE; + HKEY hKey; + + ASSERT(m_strCurrentPath.GetLength() > 0); + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_READ, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegQueryValueEx(hKey, LPCTSTR(strName), NULL, + &dwType, (LPBYTE)pRect, &dwSize) != ERROR_SUCCESS) bSuccess = FALSE; + ::RegCloseKey(hKey); + return bSuccess; +} + + + + +BOOL CRegistry::WriteBool(CString strName, BOOL bValue) +{ + ASSERT(m_strCurrentPath.GetLength() > 0); + BOOL bSuccess = TRUE; + HKEY hKey; + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_WRITE, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, + REG_BINARY, (LPBYTE)&bValue, sizeof(bValue)) + != ERROR_SUCCESS) bSuccess = FALSE; + + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + return bSuccess; +} + +BOOL CRegistry::WriteDateTime(CString strName, COleDateTime dtValue) +{ + ASSERT(m_strCurrentPath.GetLength() > 0); + BOOL bSuccess = TRUE; + HKEY hKey; + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_WRITE, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, + REG_BINARY, (LPBYTE)&dtValue, sizeof(dtValue)) + != ERROR_SUCCESS) bSuccess = FALSE; + + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + return bSuccess; +} + + +BOOL CRegistry::WriteString(CString strName, CString strValue) +{ + ASSERT(m_strCurrentPath.GetLength() > 0); + BOOL bSuccess = TRUE; + HKEY hKey; + _TCHAR sz[255]; + + if (strValue.GetLength() > 254) return FALSE; + +#ifdef _UNICODE + wstrcpy(sz, LPCTSTR(strValue)); +#else + strcpy(sz, LPCTSTR(strValue)); +#endif + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_WRITE, &hKey) != ERROR_SUCCESS) return FALSE; + +#ifdef _UNICODE + if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, + REG_SZ, (LPBYTE)sz, wstrlen(sz) + 1) + != ERROR_SUCCESS) bSuccess = FALSE; +#else + if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, + REG_SZ, (LPBYTE)sz, strlen(sz) + 1) + != ERROR_SUCCESS) bSuccess = FALSE; +#endif + + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + return bSuccess; +} + + +BOOL CRegistry::WriteFloat(CString strName, double fValue) +{ + ASSERT(m_strCurrentPath.GetLength() > 0); + BOOL bSuccess = TRUE; + HKEY hKey; + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_WRITE, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, + REG_BINARY, (LPBYTE)&fValue, sizeof(fValue)) + != ERROR_SUCCESS) bSuccess = FALSE; + + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + return bSuccess; +} + +BOOL CRegistry::WriteInt(CString strName, int nValue) +{ + ASSERT(m_strCurrentPath.GetLength() > 0); + BOOL bSuccess = TRUE; + HKEY hKey; + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_WRITE, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, + REG_BINARY, (LPBYTE)&nValue, sizeof(nValue)) + != ERROR_SUCCESS) bSuccess = FALSE; + + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + return bSuccess; +} + +BOOL CRegistry::WriteDword(CString strName, DWORD dwValue) +{ + ASSERT(m_strCurrentPath.GetLength() > 0); + BOOL bSuccess = TRUE; + HKEY hKey; + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_WRITE, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, + REG_BINARY, (LPBYTE)&dwValue, sizeof(dwValue)) + != ERROR_SUCCESS) bSuccess = FALSE; + + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + return bSuccess; +} + +BOOL CRegistry::WriteColor(CString strName, COLORREF rgbValue) +{ + ASSERT(m_strCurrentPath.GetLength() > 0); + BOOL bSuccess = TRUE; + HKEY hKey; + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_WRITE, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, + REG_BINARY, (LPBYTE)&rgbValue, sizeof(rgbValue)) + != ERROR_SUCCESS) bSuccess = FALSE; + + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + return bSuccess; +} + + +BOOL CRegistry::WriteFont(CString strName, CFont* pFont) +{ + ASSERT(m_strCurrentPath.GetLength() > 0); + BOOL bSuccess = TRUE; + HKEY hKey; + + LOGFONT lf; + pFont->GetLogFont(&lf); + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_WRITE, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, + REG_BINARY, (LPBYTE)&lf, sizeof(lf)) + != ERROR_SUCCESS) bSuccess = FALSE; + + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + return bSuccess; +} + + +BOOL CRegistry::WritePoint(CString strName, CPoint* pPoint) +{ + ASSERT(m_strCurrentPath.GetLength() > 0); + BOOL bSuccess = TRUE; + HKEY hKey; + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_WRITE, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, + REG_BINARY, (LPBYTE)pPoint, sizeof(CPoint)) + != ERROR_SUCCESS) bSuccess = FALSE; + + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + return bSuccess; +} + + +BOOL CRegistry::WriteSize(CString strName, CSize* pSize) +{ + ASSERT(m_strCurrentPath.GetLength() > 0); + BOOL bSuccess = TRUE; + HKEY hKey; + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_WRITE, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, + REG_BINARY, (LPBYTE)pSize, sizeof(CSize)) + != ERROR_SUCCESS) bSuccess = FALSE; + + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + return bSuccess; +} + +BOOL CRegistry::WriteRect(CString strName, CRect* pRect) +{ + ASSERT(m_strCurrentPath.GetLength() > 0); + BOOL bSuccess = TRUE; + HKEY hKey; + + if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0, + KEY_WRITE, &hKey) != ERROR_SUCCESS) return FALSE; + + if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, + REG_BINARY, (LPBYTE)pRect, sizeof(CRect)) + != ERROR_SUCCESS) bSuccess = FALSE; + + if (!m_bLazyWrite) ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + return bSuccess; +} +
Change 1 of 1 Show Entire File tortoise/​shellext/​Registry.h Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
 
@@ -0,0 +1,77 @@
+ + +#ifndef __REGISTRY_H__ +#define __REGISTRY_H__ + +#include <string> +typedef std::string CString; + +class CRegistry +{ +public: + CRegistry(); + ~CRegistry(); + +int m_nLastError; + +// CRegistry properties +protected: + HKEY m_hRootKey; + BOOL m_bLazyWrite; + CString m_strCurrentPath; + +public: + inline BOOL PathIsValid() { + return (m_strCurrentPath.GetLength() > 0); } + inline CString GetCurrentPath() { + return m_strCurrentPath; } + inline HKEY GetRootKey() { + return m_hRootKey; } + + +//CRegistry methods +public: + BOOL ClearKey(); + BOOL SetRootKey(HKEY hRootKey); + BOOL CreateKey(CString strKey); + BOOL DeleteKey(CString strKey); + BOOL DeleteValue(CString strName); + int GetDataSize(CString strValueName); + DWORD GetDataType(CString strValueName); + int GetSubKeyCount(); + int GetValueCount(); + BOOL KeyExists(CString strKey, HKEY hRootKey = NULL); + BOOL SetKey(CString strKey, BOOL bCanCreate); + BOOL ValueExists(CString strName); + void RenameValue(CString strOldName, CString strNewName); + + // data reading functions + COleDateTime ReadDateTime(CString strName, COleDateTime dtDefault); + double ReadFloat(CString strName, double fDefault); + CString ReadString(CString strName, CString strDefault); + int ReadInt(CString strName, int nDefault); + BOOL ReadBool(CString strName, BOOL bDefault); + COLORREF ReadColor(CString strName, COLORREF rgbDefault); + BOOL ReadFont(CString strName, CFont* pFont); + BOOL ReadPoint(CString strName, CPoint* pPoint); + BOOL ReadSize(CString strName, CSize* pSize); + BOOL ReadRect(CString strName, CRect* pRect); + DWORD ReadDword(CString strName, DWORD dwDefault); + + // data writing functions + BOOL WriteBool(CString strName, BOOL bValue); + BOOL WriteDateTime(CString strName, COleDateTime dtValue); + BOOL WriteString(CString strName, CString strValue); + BOOL WriteFloat(CString strName, double fValue); + BOOL WriteInt(CString strName, int nValue); + BOOL WriteColor(CString strName, COLORREF rgbValue); + BOOL WriteFont(CString strName, CFont* pFont); + BOOL WritePoint(CString strName, CPoint* pPoint); + BOOL WriteSize(CString strName, CSize* pSize); + BOOL WriteRect(CString strName, CRect* pRect); + BOOL WriteDword(CString strName, DWORD dwValue); + +};// end of CRegistry class definition + + +#endif \ No newline at end of file
Change 1 of 1 Show Entire File tortoise/​shellext/​ShellExt.cpp Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
@@ -0,0 +1,359 @@
+#include "stdafx.h" +#include "ShellExt.h" +#include "TortoiseUtils.h" +#include "ShellUtils.h" +#include "StringUtils.h" +#include <olectl.h> + +DEFINE_GUID(CLSID_TortoiseHg0, 0xb456dba0L, 0x7bf4, 0x478c, 0x93, 0x7a, 0x5, 0x13, 0xc, 0x2c, 0x21, 0x2e); +DEFINE_GUID(CLSID_TortoiseHg1, 0xb456dba1L, 0x7bf4, 0x478c, 0x93, 0x7a, 0x5, 0x13, 0xc, 0x2c, 0x21, 0x2e); +DEFINE_GUID(CLSID_TortoiseHg2, 0xb456dba2L, 0x7bf4, 0x478c, 0x93, 0x7a, 0x5, 0x13, 0xc, 0x2c, 0x21, 0x2e); +DEFINE_GUID(CLSID_TortoiseHg3, 0xb456dba3L, 0x7bf4, 0x478c, 0x93, 0x7a, 0x5, 0x13, 0xc, 0x2c, 0x21, 0x2e); +DEFINE_GUID(CLSID_TortoiseHg4, 0xb456dba4L, 0x7bf4, 0x478c, 0x93, 0x7a, 0x5, 0x13, 0xc, 0x2c, 0x21, 0x2e); +DEFINE_GUID(CLSID_TortoiseHg5, 0xb456dba5L, 0x7bf4, 0x478c, 0x93, 0x7a, 0x5, 0x13, 0xc, 0x2c, 0x21, 0x2e); +DEFINE_GUID(CLSID_TortoiseHg6, 0xb456dba6L, 0x7bf4, 0x478c, 0x93, 0x7a, 0x5, 0x13, 0xc, 0x2c, 0x21, 0x2e); + +UINT g_cRefThisDll = 0; +HINSTANCE g_hmodThisDll = NULL; + +HMENU hSubMenu = 0; + +typedef struct +{ + HKEY hRootKey; + LPTSTR lpszSubKey; + LPTSTR lpszValueName; + LPTSTR lpszData; +} REGSTRUCT, *LPREGSTRUCT; + +VOID _LoadResources(); +VOID _UnloadResources(); + +extern "C" +int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + TDEBUG_TRACE("DllMain"); + + if (dwReason == DLL_PROCESS_ATTACH) + { + g_hmodThisDll = hInstance; + _LoadResources(); + } + else if (dwReason == DLL_PROCESS_DETACH) + _UnloadResources(); + + return 1; +} + +STDAPI DllCanUnloadNow(void) +{ + TDEBUG_TRACE("DllCanUnloadNow"); + return (g_cRefThisDll == 0 ? S_OK : S_FALSE); +} + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut) +{ + LPWSTR pwszShellExt; + StringFromIID(rclsid, &pwszShellExt); + TDEBUG_TRACE("DllGetClassObject clsid = " << WideToMultibyte(pwszShellExt)); + *ppvOut = NULL; + + if (IsEqualIID(rclsid, CLSID_TortoiseHg0)) + { + CDllRegSxClassFactory *pcf = new CDllRegSxClassFactory(TORTOISE_OLE_UNCHANGED); + TDEBUG_TRACE("DllGetClassObject clsname = " << "CLSID_TortoiseHg0"); + return pcf->QueryInterface(riid, ppvOut); + } + else if (IsEqualIID(rclsid, CLSID_TortoiseHg1)) + { + CDllRegSxClassFactory *pcf = new CDllRegSxClassFactory(TORTOISE_OLE_ADDED); + TDEBUG_TRACE("DllGetClassObject clsname = " << "CLSID_TortoiseHg1"); + return pcf->QueryInterface(riid, ppvOut); + } + else if (IsEqualIID(rclsid, CLSID_TortoiseHg2)) + { + CDllRegSxClassFactory *pcf = new CDllRegSxClassFactory(TORTOISE_OLE_MODIFIED); + TDEBUG_TRACE("DllGetClassObject clsname = " << "CLSID_TortoiseHg2"); + return pcf->QueryInterface(riid, ppvOut); + } + + return CLASS_E_CLASSNOTAVAILABLE; +} + +VOID _LoadResources(VOID) +{ +} + +VOID _UnloadResources(VOID) +{ + if (hSubMenu) + DestroyMenu(hSubMenu); +} + +CDllRegSxClassFactory::CDllRegSxClassFactory(TortoiseOLEClass classToMake) +{ + m_cRef = 0L; + g_cRefThisDll++; + myclassToMake = classToMake; +} + +CDllRegSxClassFactory::~CDllRegSxClassFactory() +{ + g_cRefThisDll--; +} + +STDMETHODIMP +CDllRegSxClassFactory::QueryInterface(REFIID riid, LPVOID FAR *ppv) +{ + *ppv = NULL; + + if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) + { + *ppv = (LPCLASSFACTORY)this; + AddRef(); + + return NOERROR; + } + + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) +CDllRegSxClassFactory::AddRef() +{ + return ++m_cRef; +} + +STDMETHODIMP_(ULONG) +CDllRegSxClassFactory::Release() +{ + if (--m_cRef) + return m_cRef; + + delete this; + return 0L; +} + +STDMETHODIMP +CDllRegSxClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObj) +{ + *ppvObj = NULL; + + if (pUnkOuter) + return CLASS_E_NOAGGREGATION; + + LPCSHELLEXT pShellExt = new CShellExt(myclassToMake); + if (NULL == pShellExt) + return E_OUTOFMEMORY; + + return pShellExt->QueryInterface(riid, ppvObj); +} + +STDMETHODIMP +CDllRegSxClassFactory::LockServer(BOOL fLock) +{ + return NOERROR; +} + +CShellExt::CShellExt(TortoiseOLEClass tortoiseClass) + : m_ppszFileUserClickedOn(0) +{ + myTortoiseClass = tortoiseClass; + m_cRef = 0L; + m_pDataObj = NULL; + + g_cRefThisDll++; +} + +CShellExt::~CShellExt() +{ + if (m_pDataObj) + m_pDataObj->Release(); + + g_cRefThisDll--; +} + +STDMETHODIMP +CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv) +{ + std::string clsname = "UNKNOWN CLSID"; + + *ppv = NULL; + if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown)) + { + *ppv = (LPSHELLEXTINIT)this; + clsname = "IID_IShellExtInit"; + } + else if (IsEqualIID(riid, IID_IContextMenu)) + { + *ppv = (LPCONTEXTMENU)this; + clsname = "IID_IContextMenu"; + } + else if (IsEqualIID(riid, IID_IContextMenu2)) + { + *ppv = (IContextMenu2 *) this; + clsname = "IID_IContextMenu2"; + } + else if (IsEqualIID(riid, IID_IContextMenu3)) + { + *ppv = (IContextMenu3 *) this; + clsname = "IID_IContextMenu3"; + } + else if (IsEqualIID(riid, IID_IShellIconOverlayIdentifier)) + { + *ppv = (IShellIconOverlayIdentifier *) this; + clsname = "IID_IShellIconOverlayIdentifier"; + } + + TDEBUG_TRACE("CShellExt::QueryInterface: " << clsname); + + if(*ppv) + { + AddRef(); + return NOERROR; + } + + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) +CShellExt::AddRef() +{ + return ++m_cRef; +} + +STDMETHODIMP_(ULONG) +CShellExt::Release() +{ + if(--m_cRef) + return m_cRef; + + delete this; + return 0L; +} + +#if 0 +STDMETHODIMP +CShellExt::Initialize(LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hRegKey) +{ + if (m_pDataObj) + m_pDataObj->Release(); + if (pDataObj) + { + m_pDataObj = pDataObj; + pDataObj->AddRef(); + } + return NOERROR; +} + +#else + +STDMETHODIMP +CShellExt::Initialize(LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hRegKey) +{ + TCHAR name[MAX_PATH+1]; + + TDEBUG_TRACE("CShellExt::Initialize"); + TDEBUG_TRACE(" pIDFolder: " << pIDFolder); + TDEBUG_TRACE(" pDataObj: " << pDataObj); + + myFolder.clear(); + myFiles.clear(); + + if (pDataObj) + { +#if 1 + FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stg = { TYMED_HGLOBAL }; + if (SUCCEEDED(pDataObj->GetData(&fmt, &stg)) && stg.hGlobal) + { + HDROP hDrop = (HDROP) GlobalLock(stg.hGlobal); + + if (hDrop) + { + UINT uNumFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); + TDEBUG_TRACE(" hDrop uNumFiles = " << uNumFiles); + for (int i = 0; i < uNumFiles; ++i) { + if (DragQueryFile(hDrop, i, name, MAX_PATH) > 0) + { + TDEBUG_TRACE(" DragQueryFile [" << i << "] = " << name); + myFiles.push_back(name); + } + } + } + else + { + TDEBUG_TRACE(" hDrop is NULL "); + } + + GlobalUnlock(stg.hGlobal); + if (stg.pUnkForRelease) + { + IUnknown* relInterface = (IUnknown*) stg.pUnkForRelease; + relInterface->Release(); + } + } + else + { + TDEBUG_TRACE(" pDataObj->GetData failed"); + } + +#else + + STGMEDIUM medium; + FORMATETC fmte = { RegisterClipboardFormat(CFSTR_SHELLIDLIST), + NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + HRESULT hres = pDataObj->GetData(&fmte, &medium); + + if (SUCCEEDED(hres) && medium.hGlobal) + { + // Enumerate PIDLs which the user has selected + CIDA* cida = (CIDA*) GlobalLock(medium.hGlobal); + LPCITEMIDLIST parentFolder = GetPIDLFolder(cida); + TDEBUG_TRACE("Parent folder: " << GetPathFromIDList(parentFolder)); + int count = cida->cidl; + TDEBUG_TRACE("Selected items: " << count); + for (int i = 0; i < count; ++i) + { + LPCITEMIDLIST child = GetPIDLItem(cida, i); + LPITEMIDLIST absolute = AppendPIDL(parentFolder, child); + std::string name = GetPathFromIDList(absolute); + TDEBUG_TRACE("Processing " << GetPathFromIDList(absolute)); + if (IsShortcut(absolute)) + { + TDEBUG_TRACE("IsShortCut " << name); + LPITEMIDLIST target = GetShortcutTarget(absolute); + ItemListFree(absolute); + absolute = target; + name = GetPathFromIDList(target); + } + + name = GetPathFromIDList(absolute); + TDEBUG_TRACE("myFiles pusing " << name); + myFiles.push_back(name); + + ItemListFree(absolute); + } + + GlobalUnlock(medium.hGlobal); + if (medium.pUnkForRelease) + { + IUnknown* relInterface = (IUnknown*) medium.pUnkForRelease; + relInterface->Release(); + } + } +#endif + } + + // if a directory background + if (pIDFolder) + { + SHGetPathFromIDList(pIDFolder, name); + TDEBUG_TRACE(" Folder " << name); + myFolder = name; + } + + return NOERROR; +} + +#endif
Change 1 of 1 Show Entire File tortoise/​shellext/​ShellExt.def Stacked
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
@@ -0,0 +1,9 @@
+; shellext: Declares the module parameters for the DLL. + +LIBRARY TORTOISEHGSHELL +DESCRIPTION 'Shell Extensions for TortoiseHg' + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE +
Change 1 of 1 Show Entire File tortoise/​shellext/​ShellExt.h Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
@@ -0,0 +1,112 @@
+#ifndef _SHELL_EXT_H_ +#define _SHELL_EXT_H_ + +#pragma data_seg(".text") +#include <objbase.h> +#define INITGUID +#include <initguid.h> +#include <shlobj.h> +#include <shlguid.h> +#include <vector> +#include <string> +#pragma data_seg() + +#define DLLREGUNREGNAME TEXT("DLL Registerer") + +enum TortoiseOLEClass +{ + TORTOISE_OLE_INVALID, + TORTOISE_OLE_ADDED, + TORTOISE_OLE_MODIFIED, + TORTOISE_OLE_UNCHANGED, + TORTOISE_OLE_IGNORED, + TORTOISE_OLE_NOTINREPO, +}; + +// +// Factory +// +class CDllRegSxClassFactory : public IClassFactory +{ + protected: + ULONG m_cRef; + TortoiseOLEClass myclassToMake; + + public: + CDllRegSxClassFactory(TortoiseOLEClass); + ~CDllRegSxClassFactory(); + + public: + STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *); + STDMETHODIMP LockServer(BOOL); +}; + +typedef CDllRegSxClassFactory *LPCSHELLEXTCLASSFACTORY; + +// +// Shell extensions +// +class CShellExt : + public + IContextMenu3, + IShellIconOverlayIdentifier, + IShellExtInit +{ + TortoiseOLEClass myTortoiseClass; + + protected: + ULONG m_cRef; + LPDATAOBJECT m_pDataObj; + + LPTSTR *m_ppszFileUserClickedOn; // [MAX_PATH] + std::vector<std::string> myFiles; + std::string myFolder; + + protected: + void CShellExt::DoHgProc(const std::string &, bool=false, bool=false); + + public: + // context menu actions + STDMETHODIMP CM_Commit(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd); + STDMETHODIMP CM_Status(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd); + STDMETHODIMP CM_Log(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd); + STDMETHODIMP CM_About(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd); + STDMETHODIMP CM_Serve(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd); + STDMETHODIMP CM_Synch(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd); + STDMETHODIMP CM_Update(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd); + STDMETHODIMP CM_Recover(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd); + STDMETHODIMP CM_Userconf(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd); + STDMETHODIMP CM_Repoconf(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd); + + public: + CShellExt(TortoiseOLEClass); + ~CShellExt(); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR *ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IContextMenu3 + STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); + STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi); + STDMETHODIMP GetCommandString(UINT idCmd, UINT uFlags, UINT FAR *reserved, LPSTR pszName, UINT cchMax); + STDMETHODIMP HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam); + STDMETHODIMP HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult); + + // IShellIconOverlayIdentifier + STDMETHODIMP GetOverlayInfo(LPWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags); + STDMETHODIMP GetPriority(int *pPriority); + STDMETHODIMP IsMemberOf(LPCWSTR pwszPath, DWORD dwAttrib); + + // IShellExtInit + STDMETHODIMP Initialize(LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hKeyID); + }; + +typedef CShellExt *LPCSHELLEXT; + +#endif // _SHELL_EXT_H_
Show Entire File tortoise/​shellext/​ShellUtils.cpp Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Change 1 of 1 Show Entire File tortoise/​shellext/​ShellUtils.h Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
@@ -0,0 +1,128 @@
+// TortoiseCVS - a Windows shell extension for easy version control + +// Copyright (C) 2000 - Francis Irving +// <francis@flourish.org> - May 2000 + +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef SHELL_UTILS_H +#define SHELL_UTILS_H + +#include <windows.h> +#include "FixWinDefs.h" +#include <shlobj.h> +#include <string> +#include <vector> + + +// Explorer pidl data structure walking functions. +// These are probably compatible with Borland builder ones +// of the same name (judging by usenet posting snippets). +// _Who_ invented this stuff in an API? Madness. +LPCITEMIDLIST GetNextItem(LPCITEMIDLIST pidl); +int GetItemCount(LPCITEMIDLIST pidl); +UINT GetSize(LPCITEMIDLIST pidl); +LPITEMIDLIST DuplicateItem(LPMALLOC pMalloc, LPCITEMIDLIST pidl); +// And some more found from usenet, ported from Delphi... +bool IsDesktopFolder(LPCITEMIDLIST pidl); +LPITEMIDLIST AppendPIDL(LPCITEMIDLIST dest, LPCITEMIDLIST src); +// And more... +void ItemListFree(LPITEMIDLIST pidl); +bool IsEqualPIDL(LPCITEMIDLIST a, LPCITEMIDLIST b); // this possibly doesn't work at all, test it when you try to use it +std::string DisplayNamePIDL(LPCITEMIDLIST pidl); + +// From "Shell Clipboard Formats" in the MSDN library: +// << The following two macros can be used to retrieve PIDLs from a CIDA structure. +// The first takes a pointer to the structure and retrieves the PIDL of the parent folder. +// The second takes a pointer to the structure and retrieves one of the other PIDLs, +// identified by its zero-based index. >> +#define GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0]) +#define GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1]) + +// Launch a command, optionally wait for termination +bool LaunchCommand(const std::string& command, bool waitForEnd, bool minimized = false); + +// Return true if it is safe to view this file, i.e. it is not an executable +bool FileIsViewable(const std::string& filename); + +// Launch a file to be opened by the registered type in the shell +bool LaunchFile(const std::string& filename, bool waitForEnd); + +std::string DesktopFolder(); + +// Path of special folder +std::string GetSpecialFolder(int nFolder); + +// Test if PIDL points to a special folder +bool IsSpecialFolder(LPCITEMIDLIST pidl, int nFolder); + +// Get path from IDList +std::string GetPathFromIDList(LPCITEMIDLIST pidl); + +// Strips the last ID from the list +LPITEMIDLIST StripLastID(LPCITEMIDLIST pidl); + +// Get the last ID from the list +LPITEMIDLIST GetLastID(LPCITEMIDLIST pidl); + +// Bind to parent +IShellFolder* BindToParent(LPCITEMIDLIST pidl); + +// Is PIDL a shortcut +bool IsShortcut(LPCITEMIDLIST pidl); + +// Get target of a shortcut +LPITEMIDLIST GetShortcutTarget(LPCITEMIDLIST pidl); + +// Clone a PIDL +LPITEMIDLIST CloneIDList(LPCITEMIDLIST pidl); + + +// Rebuild icons +bool RebuildIcons(); + +// Notify shell of change +void ShellNotifyUpdateFile(const std::string& sFilename); + +// Notify shell of change +void ShellNotifyUpdateFiles(const std::string& sDirname, + const std::vector<std::string>& sFilenames); + +// Notify shell of change +void ShellNotifyUpdateFiles(const std::vector<std::string>& sFilenames); + +void ShellNotifyUpdateDir(const std::string& sDirname); + +// Wait while processing messages +DWORD WaitWithMsgQueue(DWORD nCount, const HANDLE* pHandles, bool fWaitAll, + DWORD dwMilliseconds); + +// Get path for iconset +std::string GetIconSetPath(const std::string& iconSet); + +// Get name of iconset +wxString GetIconSetName(const std::string& iconSet); + +// Get attributes for file (contains bugfix for SHGetFileInfo) +BOOL ShellGetFileAttributes(const char* filename, DWORD *attr); + +// Get attributes for file (contains bugfix for SHGetFileInfo) +BOOL ShellGetFileAttributesPidl(LPCITEMIDLIST pidl, DWORD *attr); + +// Get icon size +BOOL ShellGetIconSize(UINT iconsize, int *width, int *height); + + +#endif
Change 1 of 1 Show Entire File tortoise/​shellext/​ShellUtils2.cpp Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
@@ -0,0 +1,366 @@
+// TortoiseCVS - a Windows shell extension for easy version control + +// Copyright (C) 2001 - Francis Irving +// <francis@flourish.org> - May 2001 + +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#include "StdAfx.h" +#include "ShellUtils.h" +#include "StringUtils.h" + + +// We don't use SHGetSpecialFolderPath as older versions +// of Windows NT don't support it. +std::string GetSpecialFolder(int nFolder) +{ + HRESULT hr; + LPITEMIDLIST pidl = 0; + std::string result; + hr = SHGetSpecialFolderLocation(NULL, nFolder, &pidl); + if (FAILED(hr)) + goto Cleanup; + + result = GetPathFromIDList(pidl); + +Cleanup: + if (pidl) + ItemListFree(pidl); + return result; +} + + +void ItemListFree(LPITEMIDLIST pidl) +{ + if ( pidl ) + { + LPMALLOC pMalloc; + SHGetMalloc(&pMalloc); + if ( pMalloc ) + { + pMalloc->Free(pidl); + pMalloc->Release(); + } + else + { + ASSERT(false); + } + } +} + + +// Get path from IDList +std::string GetPathFromIDList(LPCITEMIDLIST pidl) +{ + std::string result; + static char dir[MAX_PATH + 1]; + + if(SHGetPathFromIDListA(pidl, dir)) + result = dir; + return result; +} + + +// Is PIDL a shortcut +bool IsShortcut(LPCITEMIDLIST pidl) +{ + TDEBUG_ENTER("IsShortcut"); + DWORD dwAttributes = SFGAO_LINK; + if (ShellGetFileAttributesPidl(pidl, &dwAttributes)) + { + if (dwAttributes & SFGAO_LINK) + { + TDEBUG_TRACE("return true"); + return true; + } + } + TDEBUG_TRACE("return false"); + return false; +} + + +// Get target of a shortcut +LPITEMIDLIST GetShortcutTarget(LPCITEMIDLIST pidl) +{ + HRESULT hr; + IShellLink *pShLink = 0; + IPersistFile *ppf = 0; + std::wstring wsPath; + LPITEMIDLIST pidlResult = 0; + + // If it's not a shortcut, exit + if (!IsShortcut(pidl)) + { + pidlResult = CloneIDList(pidl); + goto Cleanup; + } + + // get path of shortcut + wsPath = MultibyteToWide(GetPathFromIDList(pidl)); + + hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + IID_IShellLink, (LPVOID*) &pShLink); + + if (FAILED(hr)) + goto Cleanup; + + hr = pShLink->QueryInterface(IID_IPersistFile, (LPVOID*) &ppf); + if (FAILED(hr)) + goto Cleanup; + + hr = ppf->Load(wsPath.c_str(), STGM_READ); + if (FAILED(hr)) + goto Cleanup; + + + hr = pShLink->Resolve(GetDesktopWindow(), SLR_NO_UI); + if (FAILED(hr)) + goto Cleanup; + + hr = pShLink->GetIDList(&pidlResult); + if (FAILED(hr)) + goto Cleanup; + +Cleanup: + if (pShLink) + pShLink->Release(); + + if (ppf) + ppf->Release(); + + return pidlResult; +} + + +// Returns the concatination of the two PIDLs. Neither passed PIDLs are +// freed so it is up to the caller to free them. +LPITEMIDLIST AppendPIDL(LPCITEMIDLIST dest, LPCITEMIDLIST src) +{ + LPMALLOC pMalloc; + if (!SUCCEEDED(SHGetMalloc(&pMalloc))) + return NULL; + + int destSize = 0; + int srcSize = 0; + + // Appending a PIDL to the DesktopPIDL is invalid so don't allow it. + if (dest != NULL && !IsDesktopFolder(dest)) + destSize = GetSize(dest) - sizeof(dest->mkid.cb); + + if (src != NULL) + srcSize = GetSize(src); + + LPITEMIDLIST sum = (LPITEMIDLIST)pMalloc->Alloc(destSize + srcSize); + if (sum != NULL) + { + if (dest != NULL) + CopyMemory((char*)sum, dest, destSize); + if (src != NULL) + CopyMemory((char*)sum + destSize, src, srcSize); + } + + pMalloc->Release(); + return sum; +} + + +// Get attributes for file (contains bugfix for SHGetFileInfo) +BOOL MyShellGetFileAttr(const void* data, DWORD *attr, bool bIsPidl) +{ + TDEBUG_ENTER("MyShellGetFileAttr"); +#ifndef UNICODE + // Workaround for NT4 bug: SHGetFileInfoA doesn't work correclty, + // so use SHGetFileInfoW + + if (WindowsVersionIsNT4()) + { + TDEBUG_TRACE("Windows NT4 workaround"); + SHFILEINFOW fi; + std::wstring ws; + DWORD dwFlags = SHGFI_ATTRIBUTES; + if (attr == 0) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + if (*attr != 0) + { + TDEBUG_TRACE("Attributes: " << *attr); + fi.dwAttributes = *attr; + dwFlags |= SHGFI_ATTR_SPECIFIED; + } + if (bIsPidl) + { + TDEBUG_TRACE("It's a PIDL"); + dwFlags |= SHGFI_PIDL; + } + else + { + TDEBUG_TRACE("It's a path:" << (const char *) data); + ws = MultibyteToWide((const char *) data, 0); + data = ws.c_str(); + } + + DWORD dwResult = SHGetFileInfoW((LPWSTR) data, 0, &fi, sizeof(fi), + dwFlags); + *attr = fi.dwAttributes; + return (dwResult != 0); + } +#endif + + SHFILEINFOA fi; + DWORD dwFlags = SHGFI_ATTRIBUTES; + if (attr != 0) + { + fi.dwAttributes = *attr; + dwFlags |= SHGFI_ATTR_SPECIFIED; + } + if (bIsPidl) + dwFlags |= SHGFI_PIDL; + + DWORD dwResult = SHGetFileInfoA((LPCSTR) data, 0, &fi, sizeof(fi), dwFlags); + *attr = fi.dwAttributes; + return (dwResult != 0); +} + + +// Get attributes for file (contains bugfix for SHGetFileInfo) +BOOL ShellGetFileAttributes(const char* filename, DWORD *attr) +{ + return MyShellGetFileAttr(filename, attr, false); +} + + +// Get attributes for file (contains bugfix for SHGetFileInfo) +BOOL ShellGetFileAttributesPidl(LPCITEMIDLIST pidl, DWORD *attr) +{ + return MyShellGetFileAttr(pidl, attr, true); +} + + +// Tests the passed PIDL to see if it is the root Desktop Folder +bool IsDesktopFolder(LPCITEMIDLIST pidl) +{ + if (pidl != NULL) + return pidl->mkid.cb == 0; + else + return false; +} + + +bool IsEqualPIDL(LPCITEMIDLIST a, LPCITEMIDLIST b) +{ + UINT asiz = GetSize(a); + UINT bsiz = GetSize(b); + if (asiz != bsiz) + return false; + + if (memcmp(a, b, asiz) == 0) + return true; + + return false; +} + +LPCITEMIDLIST GetNextItem(LPCITEMIDLIST pidl) +{ + if (pidl == NULL) + return NULL; + + // Get size of the item identifier we are on + int cb = pidl->mkid.cb; + + // If zero, then end of list + if (cb == 0) + return NULL; + + // Move on + pidl = (LPITEMIDLIST) (((LPBYTE)pidl) + cb); + + // Return NULL if null-terminating, or pidl otherwise + return (pidl->mkid.cb == 0) ? NULL : (LPITEMIDLIST) pidl; +} + +int GetItemCount(LPCITEMIDLIST pidl) +{ + int count = 0; + + while (pidl != 0) + { + count++; + pidl = GetNextItem(pidl); + } + + return count; +} + +UINT GetSize(LPCITEMIDLIST pidl) +{ + UINT total = 0; + if (pidl) + { + total += sizeof(pidl->mkid.cb); + while (pidl) + { + total += pidl->mkid.cb; + pidl = GetNextItem(pidl); + } + } + return total; +} + +LPITEMIDLIST DuplicateItem(LPMALLOC pMalloc, LPCITEMIDLIST pidl) +{ + int cb = pidl->mkid.cb; + if (cb == 0) + return NULL; + + LPITEMIDLIST pidlRet = (LPITEMIDLIST)pMalloc->Alloc(cb + sizeof(USHORT)); + if (pidlRet == NULL) + return NULL; + + CopyMemory(pidlRet, pidl, cb); + *((USHORT*) (((LPBYTE)pidlRet) + cb)) = 0; + return pidlRet; +} + + +// Clone a PIDL +LPITEMIDLIST CloneIDList(LPCITEMIDLIST pidl) +{ + LPITEMIDLIST pidlResult = 0; + DWORD dwSize; + LPMALLOC pMalloc; + + if (!SUCCEEDED(SHGetMalloc(&pMalloc))) + goto Cleanup; + + dwSize = GetSize(pidl); + if (dwSize == 0) + goto Cleanup; + + pidlResult = (LPITEMIDLIST) pMalloc->Alloc(dwSize); + if (!pidlResult) + goto Cleanup; + + CopyMemory(pidlResult, pidl, dwSize); + +Cleanup: + if (pMalloc) + pMalloc->Release(); + + return pidlResult; +} +
This file's diff was not loaded because this changeset is very large. Load changes
Change 1 of 1 Show Entire File tortoise/​shellext/​StringUtils.h Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
@@ -0,0 +1,150 @@
+// TortoiseCVS - a Windows shell extension for easy version control + +// Copyright (C) 2002 - Francis Irving +// <francis@flourish.org> - May 2002 + +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef _STRING_UTILS_H +#define _STRING_UTILS_H + +#include <string> +//#include <wx/string.h> +#include <vector> +#include <map> +#include <windows.h> +//#include "FixWinDefs.h" + + +#ifdef _MSC_VER + // Fancier GUI Visual C++ asserts + #include <crtdbg.h> +#else + // Standard C assert + #include <assert.h> +#ifndef _ASSERT + #define _ASSERT assert +#endif + + // This seems needed by Borland and GCC. + // Who else? What standard is it? + #include <errno.h> + #ifndef ENOMEM + #define ENOMEM 12 + #endif +#endif + +#ifndef ASSERT + #define ASSERT _ASSERT +#endif + +// From: http://www.kbcafe.com/articles/cplusplus.tricks.html +template<class T> void FindAndReplace(T& source, const T& find, const T& replace) +{ + size_t j; + for (j = 0; (j = source.find(find, j)) != T::npos;) + { + source.replace(j, find.length(), replace); + j += replace.length(); + } +} + +// Return the length of the longest string in the vector. +int MaxStringLength(const std::vector<std::string>& stringvec); + +void MakeLowerCase(std::string& s); + +void MakeUpperCase(std::string& s); + +// Remove leading whitespaces from a string +std::string TrimLeft(const std::string& str); + + +// Remove trailing whitespaces from a string +std::string TrimRight(const std::string& str); + + +// Remove leading and trailing whitespaces from a string +std::string Trim(const std::string& str); + +// Test if string starts with substr +bool StartsWith(const std::string& str, const std::string& substr); + +// Quotes a string +std::string Quote(const std::string& str); + +// Cuts the first token off a delimited list +std::string CutFirstToken(std::string& sList, const std::string sDelimiter); + +// Printf returning a std::string +//wxString Printf(const wxChar* format, ...); + +std::string PrintfA(const char* format, ...); + +// Convert Unicode string to multibyte string +std::string WideToMultibyte(const std::wstring& wide, UINT CodePage = CP_ACP); + +// Convert multibyte string to Unicode string +std::wstring MultibyteToWide(const std::string& multibyte, UINT CodePage = CP_ACP); + +#if wxUSE_UNICODE +#define wxText(xxx) MultibyteToWide(xxx) +#define wxTextCStr(xxx) MultibyteToWide(xxx).c_str() +#define wxAscii(xxx) WideToMultibyte(xxx) +#else +#define wxText(xxx) xxx +#define wxTextCStr(xxx) (xxx).c_str() +#define wxAscii(xxx) xxx +#endif + +// Serialize a vector of strings +std::string SerializeStringVector(const std::vector<std::string>& vStrings, + const std::string& sDelimiter); + +// Expand environment strings +std::string ExpandEnvStrings(const std::string& str); + +#if wxUSE_UNICODE +wxString ExpandEnvStrings(const wxString& str); +#endif + +// Replace parameters (%something) +std::string ReplaceParams(const std::string& str, + const std::map<std::string, std::string> params); + +// comparison function object +class less_nocase +{ +public: + bool operator()(const std::string& x, const std::string& y) const + { + std::string::const_iterator p = x.begin(); + std::string::const_iterator q = y.begin(); + + while (p != x.end() && q != y.end() && toupper(*p) == toupper(*q)) + ++p, ++q; + + if (p == x.end()) // Reached end of x: Return true if y is longer than x + return q != y.end(); + + if (q == y.end()) // Reached end of y, but not x, so x is longer than y + return false; + + return toupper(*p) < toupper(*q); + } +}; + + +#endif
Change 1 of 1 Show Entire File tortoise/​shellext/​ThgShell.iss Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@@ -0,0 +1,33 @@
+[Setup] +AppCopyright=Copyright 2007 TK Soh and others +AppName=TortoiseHg +AppVerName=TortoiseHg snapshot +;InfoAfterFile=iss/postinstall.txt +;LicenseFile=COPYING.txt +ShowLanguageDialog=yes +AppPublisher=TK Soh and others +AppPublisherURL=http://tortoisehg.sourceforge.net/ +AppSupportURL=http://tortoisehg.sourceforge.net/ +AppUpdatesURL=http://tortoisehg.sourceforge.net/ +AppID=TortoiseHg +AppContact=teekaysoh@gmail.com +OutputBaseFilename=THgShell_setup +DefaultDirName={sd}\TortoiseHg +;SourceDir=. +VersionInfoDescription=TortoiseHg +VersionInfoCopyright=Copyright 2007 TK Soh and others +VersionInfoCompany=TK Soh and others +InternalCompressLevel=max +SolidCompression=true +;SetupIconFile=icons\tortoise\hg.ico +AllowNoIcons=true +DefaultGroupName=TortoiseHg +PrivilegesRequired=poweruser +;AlwaysRestart=yes +SetupLogging=yes + +[Files] +Source: THgShell.dll; DestDir: {app}; Flags: ignoreversion +Source: ..\..\icons\*; DestDir: {app}\icons ; Flags: ignoreversion recursesubdirs createallsubdirs + +#include "registry.iss"
This file's diff was not loaded because this changeset is very large. Load changes
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoise/​shellext/​registry.iss Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoise/​shellext/​stdafx.h Stacked
This file's diff was not loaded because this changeset is very large. Load changes