by
Changes to 36 files · Browse files at 5ddaccd255af Showing diff from parent 52c295a055d6 6c34798f128d Diff from another changeset...
|
|
|
@@ -0,0 +1,286 @@ + import os
+import win32api
+import win32con
+from win32com.shell import shell, shellcon
+import _winreg
+from mercurial import hg, cmdutil, util
+from mercurial import repo as _repo
+import thgutil
+import sys
+import win32serviceutil
+import win32service
+import win32event
+import win32pipe
+import win32file
+import pywintypes
+import winerror
+
+PIPENAME = "\\\\.\\pipe\\PyPipeService"
+PIPEBUFSIZE = 4096
+
+# FIXME: quick workaround traceback caused by missing "closed"
+# attribute in win32trace.
+from mercurial import ui
+def write_err(self, *args):
+ for a in args:
+ sys.stderr.write(str(a))
+ui.ui.write_err = write_err
+
+# file/directory status
+UNCHANGED = "unchanged"
+ADDED = "added"
+MODIFIED = "modified"
+UNKNOWN = "unknown"
+NOT_IN_REPO = "n/a"
+
+# file status cache
+CACHE_TIMEOUT = 5000
+overlay_cache = {}
+cache_tick_count = 0
+cache_root = None
+cache_pdir = None
+
+# some misc constants
+S_OK = 0
+S_FALSE = 1
+
+def add_dirs(list):
+ dirs = set()
+ for f in list:
+ dir = os.path.dirname(f)
+ if dir in dirs:
+ continue
+ while dir:
+ dirs.add(dir)
+ dir = os.path.dirname(dir)
+ list.extend(dirs)
+
+def get_hg_state(upath):
+ """
+ Get the state of a given path in source control.
+ """
+ global overlay_cache, cache_tick_count
+ global cache_root, cache_pdir
+
+ #print "called: _get_state(%s)" % path
+ tc = win32api.GetTickCount()
+
+ try:
+ # handle some Asian charsets
+ path = upath.encode('mbcs')
+ except:
+ path = upath
+
+ print "get_hg_state: path =", path
+ if not path:
+ return UNKNOWN
+
+ # check if path is cached
+ pdir = os.path.dirname(path)
+ if cache_pdir == pdir and overlay_cache:
+ if tc - cache_tick_count < CACHE_TIMEOUT:
+ try:
+ status = overlay_cache[path]
+ except:
+ status = UNKNOWN
+ print "%s: %s (cached)" % (path, status)
+ return status
+ else:
+ print "Timed out!!"
+ overlay_cache.clear()
+
+ # path is a drive
+ if path.endswith(":\\"):
+ overlay_cache[path] = UNKNOWN
+ return NOT_IN_REPO
+
+ # open repo
+ if cache_pdir == pdir:
+ root = cache_root
+ else:
+ print "find new root"
+ cache_pdir = pdir
+ cache_root = root = thgutil.find_root(pdir)
+ print "_get_state: root = ", root
+ if root is None:
+ print "_get_state: not in repo"
+ overlay_cache = {None : None}
+ cache_tick_count = win32api.GetTickCount()
+ return NOT_IN_REPO
+
+ try:
+ tc1 = win32api.GetTickCount()
+ repo = hg.repository(ui.ui(), path=root)
+ print "hg.repository() took %d ticks" % (win32api.GetTickCount() - tc1)
+
+ # check if to display overlay icons in this repo
+ global_opts = ui.ui().configlist('tortoisehg', 'overlayicons', [])
+ repo_opts = repo.ui.configlist('tortoisehg', 'overlayicons', [])
+
+ print "%s: global overlayicons = " % path, global_opts
+ print "%s: repo overlayicons = " % path, repo_opts
+ is_netdrive = thgutil.netdrive_status(path) is not None
+ if (is_netdrive and 'localdisks' in global_opts) \
+ or 'False' in repo_opts:
+ print "%s: overlayicons disabled" % path
+ overlay_cache = {None : None}
+ cache_tick_count = win32api.GetTickCount()
+ return NOT_IN_REPO
+ except _repo.RepoError:
+ # We aren't in a working tree
+ print "%s: not in repo" % dir
+ overlay_cache[path] = UNKNOWN
+ return NOT_IN_REPO
+
+ # get file status
+ tc1 = win32api.GetTickCount()
+
+ modified, added, removed, deleted = [], [], [], []
+ unknown, ignored, clean = [], [], []
+ files = []
+ try:
+ matcher = cmdutil.match(repo, [pdir])
+ modified, added, removed, deleted, unknown, ignored, clean = \
+ repo.status(match=matcher, ignored=True,
+ clean=True, unknown=True)
+
+ # add directory status to list
+ for grp in (clean,modified,added,removed,deleted,ignored,unknown):
+ add_dirs(grp)
+ except util.Abort, inst:
+ print "abort: %s" % inst
+ print "treat as unknown : %s" % path
+ return UNKNOWN
+
+ print "status() took %d ticks" % (win32api.GetTickCount() - tc1)
+
+ # cached file info
+ tc = win32api.GetTickCount()
+ overlay_cache = {}
+ for grp, st in (
+ (ignored, UNKNOWN),
+ (unknown, UNKNOWN),
+ (clean, UNCHANGED),
+ (added, ADDED),
+ (removed, MODIFIED),
+ (deleted, MODIFIED),
+ (modified, MODIFIED)):
+ for f in grp:
+ fpath = os.path.join(repo.root, os.path.normpath(f))
+ overlay_cache[fpath] = st
+
+ if path in overlay_cache:
+ status = overlay_cache[path]
+ else:
+ status = overlay_cache[path] = UNKNOWN
+ print "%s: %s" % (path, status)
+ cache_tick_count = win32api.GetTickCount()
+ return status
+
+class PipeServer:
+ def __init__(self):
+ # Create an event which we will use to wait on.
+ # The "service stop" request will set this event.
+ self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
+
+ # We need to use overlapped IO for this, so we dont block when
+ # waiting for a client to connect. This is the only effective way
+ # to handle either a client connection, or a service stop request.
+ self.overlapped = pywintypes.OVERLAPPED()
+
+ # And create an event to be used in the OVERLAPPED object.
+ self.overlapped.hEvent = win32event.CreateEvent(None,0,0,None)
+
+ def SvcDoRun(self):
+ # We create our named pipe.
+ pipeName = PIPENAME
+ openMode = win32pipe.PIPE_ACCESS_DUPLEX | win32file.FILE_FLAG_OVERLAPPED
+ pipeMode = win32pipe.PIPE_TYPE_MESSAGE
+
+ # When running as a service, we must use special security for the pipe
+ sa = pywintypes.SECURITY_ATTRIBUTES()
+ # Say we do have a DACL, and it is empty
+ # (ie, allow full access!)
+ sa.SetSecurityDescriptorDacl ( 1, None, 0 )
+
+ pipeHandle = win32pipe.CreateNamedPipe(pipeName,
+ openMode,
+ pipeMode,
+ win32pipe.PIPE_UNLIMITED_INSTANCES,
+ 0, 0, 6000, # default buffers, and 6 second timeout.
+ sa)
+
+ # Loop accepting and processing connections
+ while 1:
+ try:
+ hr = win32pipe.ConnectNamedPipe(pipeHandle, self.overlapped)
+ except pywintypes.error, inst:
+ print "Error connecting pipe: ", inst
+ pipeHandle.Close()
+ break
+
+ if hr==winerror.ERROR_PIPE_CONNECTED:
+ # Client is fast, and already connected - signal event
+ win32event.SetEvent(self.overlapped.hEvent)
+ # Wait for either a connection, or a service stop request.
+ timeout = win32event.INFINITE
+ waitHandles = self.hWaitStop, self.overlapped.hEvent
+ rc = win32event.WaitForMultipleObjects(waitHandles, 0, timeout)
+ if rc==win32event.WAIT_OBJECT_0:
+ # Stop event
+ break
+ else:
+ # read pipe and process request
+ try:
+ hr, data = win32file.ReadFile(pipeHandle, PIPEBUFSIZE)
+ message = "Processed %d bytes: '%s'" % (len(data), data)
+ print (message)
+
+ if not data:
+ raise SystemExit # signal by dispatch terminate
+
+ try:
+ data = data.decode('mbcs')
+ except:
+ pass
+
+ try:
+ status = get_hg_state(data)
+ except SystemExit:
+ raise SystemExit # interrupted by thread2.terminate()
+ except:
+ import traceback
+ print "WARNING: something went wrong in get_hg_state()"
+ print traceback.format_exc()
+ status = "ERROR"
+
+ win32file.WriteFile(pipeHandle, status)
+
+ # And disconnect from the client.
+ win32pipe.DisconnectNamedPipe(pipeHandle)
+ except win32file.error:
+ # Client disconnected without sending data
+ # or before reading the response.
+ # Thats OK - just get the next connection
+ continue
+
+if __name__ == '__main__':
+ import sys
+ if '--server' in sys.argv:
+ svc = PipeServer()
+ svc.SvcDoRun()
+ elif '--client' in sys.argv:
+ for x in sys.argv[1:]:
+ if x.startswith('-'):
+ continue
+ path = os.path.abspath(x)
+ try:
+ status = win32pipe.CallNamedPipe(PIPENAME, path, PIPEBUFSIZE, 0)
+ except pywintypes.error, inst:
+ print "can't access named pipe '%s'" % PIPENAME
+ sys.exit()
+ print "%s = %s" % (path, status)
+ else:
+ print "usage:\n%s [--server|--client]" % sys.argv[0]
+
+
|
|
|
@@ -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;
+}
|
|
|
@@ -0,0 +1,307 @@ +
+// Copyright (C) 2009 Benjamin Pollack
+// Copyright (C) 2009 Adrian Buehlmann
+//
+// 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, see <http://www.gnu.org/licenses/>.
+
+#include "stdafx.h"
+
+#include "Directory.h"
+#include "Winstat.h"
+
+
+Directory::Directory(
+ Directory* p, const std::string& n, const std::string& basepath
+):
+ parent_(p), name_(n), tickcount_(0), status_(-1)
+{
+ if (n.empty())
+ path_ = basepath;
+ else if (basepath.empty())
+ path_ = n;
+ else
+ path_ = basepath + '/' + n;
+}
+
+
+Directory::~Directory()
+{
+ for (DirsT::iterator i = subdirs_.begin(); i != subdirs_.end(); ++i)
+ {
+ delete *i;
+ }
+}
+
+
+int splitbase(const std::string& n, std::string& base, std::string& rest)
+{
+ if (n.empty())
+ return 0;
+
+ size_t x = n.find_first_of ('/');
+ if (x == std::string::npos)
+ {
+ base.clear();
+ rest = n;
+ return 1;
+ }
+
+ if (x == 0 || x == n.length()-1)
+ return 0;
+
+ base = n.substr(0, x);
+ rest = n.substr(x+1);
+
+ return 1;
+}
+
+
+int Directory::add(const std::string& n_in, Direntry& e)
+{
+ std::string base;
+ std::string rest;
+
+ std::string n = n_in;
+ Directory* cur = this;
+
+ for (;;)
+ {
+
+ if (!splitbase(n, base, rest)) {
+ TDEBUG_TRACE("Directory(" << path() << ")::add(" << n_in
+ << "): splitbase returned 0");
+ return 0;
+ }
+
+ if (base.empty())
+ {
+ e.name = n;
+ cur->files_.push_back(e);
+ return 1;
+ }
+
+ Directory* d = 0;
+ for (DirsT::iterator i = cur->subdirs_.begin();
+ i != cur->subdirs_.end(); ++i)
+ {
+ if ((*i)->name_ == base) {
+ d = *i;
+ break;
+ }
+ }
+
+ if (!d)
+ {
+ d = new Directory(cur, base, cur->path());
+ cur->subdirs_.push_back(d);
+ }
+
+ n = rest;
+ cur = d;
+ }
+}
+
+
+const Direntry* Directory::get(const std::string& n_in) const
+{
+ std::string base;
+ std::string rest;
+
+ std::string n = n_in;
+ const Directory* cur = this;
+
+ for (;;)
+ {
+ loopstart:
+
+ if (!splitbase(n, base, rest))
+ {
+ TDEBUG_TRACE("Directory(" << path() << ")::get("
+ << n_in << "): splitbase returned 0");
+ return 0;
+ }
+
+ if (base.empty())
+ {
+ for (FilesT::const_iterator i = cur->files_.begin();
+ i != cur->files_.end(); ++i)
+ {
+ if (i->name == n)
+ return &(*i);
+ }
+ return 0;
+ }
+
+ for (DirsT::const_iterator i = cur->subdirs_.begin();
+ i != cur->subdirs_.end(); ++i)
+ {
+ if ((*i)->name_ == base)
+ {
+ cur = *i;
+ n = rest;
+ goto loopstart;
+ }
+ }
+
+ TDEBUG_TRACE("Directory(" << path() << ")::get("
+ << n_in << "): unknown subdir");
+ return 0;
+ }
+}
+
+
+Directory* Directory::getdir(const std::string& n_in)
+{
+ std::string base;
+ std::string rest;
+
+ std::string n = n_in;
+ const Directory* cur = this;
+
+ for (;;)
+ {
+ loopstart:
+
+ if (!splitbase(n, base, rest))
+ {
+ TDEBUG_TRACE("Directory(" << path() << ")::getdir("
+ << n_in << "): splitbase returned 0");
+ return 0;
+ }
+
+ const bool leaf = base.empty();
+ const std::string& searchstr = (leaf ? n : base);
+
+ for (DirsT::const_iterator i = cur->subdirs_.begin();
+ i != cur->subdirs_.end(); ++i)
+ {
+ if ((*i)->name_ == searchstr)
+ {
+ if (leaf)
+ return *i;
+ cur = *i;
+ n = rest;
+ goto loopstart;
+ }
+ }
+
+ return 0;
+ }
+}
+
+
+char Directory::status_imp(const std::string& hgroot)
+{
+ bool added = false;
+
+ std::vector<Directory*> todo;
+ todo.push_back(this);
+
+ Winstat stat;
+ std::string basepath;
+
+ while (!todo.empty())
+ {
+ Directory* const d = todo.back();
+ todo.pop_back();
+
+ //TDEBUG_TRACE("Directory(" << path() << ")::status_imp: "
+ // "popped '" << d->path() << "'");
+
+ if (!d->files_.empty())
+ {
+ basepath = hgroot + "/" + d->path() + "/";
+
+ for (FilesT::iterator i = d->files_.begin(); i != d->files_.end(); ++i)
+ {
+ if (i->state == 'r')
+ return 'M'; // file was removed, report dir as modified
+
+ std::string p = basepath + i->name;
+ if (0 != stat.lstat(p.c_str()))
+ return 'M'; // file is missing, report dir as modified
+
+ char s = i->status(stat);
+
+ if (s == 'M')
+ return 'M';
+ if (s == 'A')
+ added = true;
+ }
+ }
+
+ todo.insert(todo.end(), d->subdirs_.begin(), d->subdirs_.end());
+ }
+
+ if (added)
+ return 'A';
+
+ return 'C';
+}
+
+
+char Directory::status(const std::string& hgroot)
+{
+ if (status_ != -1)
+ {
+ unsigned tc = GetTickCount();
+ if (tc - tickcount_ < 3000) {
+ return status_;
+ }
+ }
+
+ status_ = status_imp(hgroot);
+ tickcount_ = GetTickCount();
+
+ return status_;
+}
+
+
+void Directory::print() const
+{
+ for (DirsT::const_iterator i = subdirs_.begin(); i != subdirs_.end(); ++i)
+ {
+ const Directory* d = *i;
+ if (!d)
+ {
+ TDEBUG_TRACE("Directory(" << path() << ")::print: error: d is 0");
+ return;
+ }
+ d->print();
+ }
+
+ std::string base = path();
+
+ time_t t;
+ std::string s;
+ char* ctime_res = 0;
+
+ for (FilesT::const_iterator i = files_.begin(); i != files_.end(); ++i)
+ {
+ std::string p = (!base.empty() ? base + "/" + i->name : i->name);
+ t = i->mtime;
+ ctime_res = ctime(&t);
+ if (ctime_res) {
+ s = ctime_res;
+ s.resize(s.size() - 1); // strip ending '\n'
+ }
+ else {
+ s = "unset";
+ }
+ printf(
+ "%c %6o %10u %-24s %s\n",
+ i->state, i->mode, i->size, s.c_str(), p.c_str()
+ );
+ }
+}
|
|
@@ -0,0 +1,62 @@ +
+// Copyright (C) 2009 Benjamin Pollack
+// Copyright (C) 2009 Adrian Buehlmann
+//
+// 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, see <http://www.gnu.org/licenses/>.
+
+#ifndef DIRECTORY_H
+#define DIRECTORY_H
+
+#include "Direntry.h"
+
+#include <vector>
+#include <string>
+
+
+class Directory
+{
+ typedef std::vector<Directory*> DirsT;
+ typedef std::vector<Direntry> FilesT;
+
+ Directory* const parent_;
+ const std::string name_;
+ std::string path_;
+
+ DirsT subdirs_;
+ FilesT files_;
+
+ unsigned tickcount_;
+ char status_;
+
+public:
+ Directory(Directory* p, const std::string& n, const std::string& basepath);
+ ~Directory();
+
+ const std::string& path() const { return path_; }
+
+ int add(const std::string& relpath, Direntry& e);
+
+ const Direntry* get(const std::string& relpath) const;
+ Directory* Directory::getdir(const std::string& n);
+
+ char status(const std::string& hgroot);
+
+ void print() const;
+
+private:
+ char status_imp(const std::string& hgroot);
+};
+
+#endif
+
|
|
@@ -0,0 +1,70 @@ +
+// Copyright (C) 2009 Benjamin Pollack
+// Copyright (C) 2009 Adrian Buehlmann
+//
+// 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, see <http://www.gnu.org/licenses/>.
+
+#include "stdafx.h"
+
+#include "Direntry.h"
+#include "Winstat.h"
+
+
+int Direntry::read(FILE* f, std::vector<char>& relpath)
+{
+ if (fread(&state, sizeof(state), 1, f) != 1)
+ return 0;
+
+ unsigned length = 0;
+
+ fread(&mode, sizeof(mode), 1, f);
+ fread(&size, sizeof(size), 1, f);
+ fread(&mtime, sizeof(mtime), 1, f);
+ fread(&length, sizeof(length), 1, f);
+
+ mode = ntohl(mode);
+ size = ntohl(size);
+ mtime = ntohl(mtime);
+ length = ntohl(length);
+
+ relpath.resize(length + 1, 0);
+ fread(&relpath[0], sizeof(char), length, f);
+ relpath[length] = 0;
+
+ return 1;
+}
+
+
+char Direntry::status(const Winstat& stat) const
+{
+ switch (this->state)
+ {
+ case 'n':
+ if (this->mtime == (unsigned)stat.mtime
+ && this->size == (unsigned)stat.size
+ )
+ return 'C';
+ else
+ return 'M';
+ case 'm':
+ return 'M';
+ case 'r':
+ return 'R';
+ case 'a':
+ return 'A';
+ default:
+ return '?';
+ }
+}
+
|
|
@@ -0,0 +1,49 @@ +
+// Copyright (C) 2009 Benjamin Pollack
+// Copyright (C) 2009 Adrian Buehlmann
+//
+// 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, see <http://www.gnu.org/licenses/>.
+
+#ifndef DIRENTRY_H
+#define DIRENTRY_H
+
+#include <vector>
+
+class Winstat;
+
+class Direntry
+{
+public:
+ unsigned char state;
+ unsigned mode;
+ unsigned size;
+ unsigned mtime;
+
+ std::string name;
+
+ int read(FILE* f, std::vector<char>& relpath);
+ char status(const Winstat& stat) const;
+
+private:
+ static uint32_t ntohl(uint32_t x)
+ {
+ return ((x & 0x000000ffUL) << 24) |
+ ((x & 0x0000ff00UL) << 8) |
+ ((x & 0x00ff0000UL) >> 8) |
+ ((x & 0xff000000UL) >> 24);
+ }
+};
+
+#endif
+
|
|
@@ -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 */
|
|
@@ -0,0 +1,79 @@ + #include "stdafx.h"
+#include "ShellExt.h"
+#include "TortoiseUtils.h"
+#include "StringUtils.h"
+#include "PipeUtils.h"
+#include "dirstate.h"
+
+#include <shlwapi.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;
+}
+
+
+STDMETHODIMP CShellExt::IsMemberOf(LPCWSTR pwszPath, DWORD /* dwAttrib */)
+{
+ std::string path = WideToMultibyte(pwszPath);
+
+ char filterStatus = 0;
+ if (myTortoiseClass == TORTOISE_OLE_ADDED)
+ filterStatus = 'A';
+
+ char status = 0;
+ if (!HgQueryDirstate(path, filterStatus, status))
+ return S_FALSE;
+
+ if (myTortoiseClass == TORTOISE_OLE_ADDED && status == 'A')
+ return S_OK;
+ else if (myTortoiseClass == TORTOISE_OLE_MODIFIED && status == 'M')
+ return S_OK;
+ else if (myTortoiseClass == TORTOISE_OLE_UNCHANGED && status == 'C')
+ return S_OK;
+
+ return S_FALSE;
+}
|
|
@@ -0,0 +1,44 @@ +
+OBJECTS_DIRSTATE = TortoiseUtils.o Direntry.o Directory.o Winstat.o
+
+OBJECTS_THGSGELL = $(OBJECTS_DIRSTATE) \
+ ContextMenu.o \
+ IconOverlay.o \
+ MenuActions.o \
+ ShellExt.o \
+ PipeUtils.o \
+ ShellUtils2.o \
+ StringUtils.o \
+ dirstate.o
+
+BASE_LDFLAGS=-lole32 -lkernel32 -luser32 -lgdi32 -lshlwapi -lwininet \
+ -lwinmm -luuid
+
+DEFFILE=ShellExt.def
+
+LDFLAGS_THGSGELL=$(BASE_LDFLAGS) -L/lib \
+ -Wl,--subsystem,windows,--enable-stdcall-fixup,$(DEFFILE) \
+ -mwindows -shared
+
+LDFLAGS_DIRSTATE=$(BASE_LDFLAGS) \
+ -Wl,--subsystem,console,--enable-stdcall-fixup \
+ -mwindows
+
+# set DEBUG env var to 1 to enable debug trace
+ifeq ($(DEBUG),1)
+CXXFLAGS+=-D_DEBUG
+endif
+
+all: THgShell.dll dirstate.exe PipeUtils.exe
+
+THgShell.dll: $(OBJECTS_THGSGELL)
+ g++ -o $@ $(OBJECTS_THGSGELL) $(LDFLAGS_THGSGELL)
+
+PipeUtils.exe: PipeUtils.cpp PipeUtils.h StringUtils.o TortoiseUtils.o
+ g++ -o $@ $(CXXFLAGS) -DAPPMAIN $< StringUtils.o TortoiseUtils.o
+
+dirstate.exe: dirstate.cpp dirstate.h $(OBJECTS_DIRSTATE)
+ g++ -o $@ $(CXXFLAGS) -DAPPMAIN $< $(OBJECTS_DIRSTATE) $(LDFLAGS_DIRSTATE)
+
+clean:
+ rm -f *.o *.dll *.exe
|
|
|
@@ -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;
+}
|
|
@@ -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
|
|
@@ -0,0 +1,6 @@ + #ifndef __NTServiceManager_PipeUtils_Defined__
+#define __NTServiceManager_PipeUtils_Defined__
+
+int query_pipe(LPCSTR lpszWrite, TCHAR *chReadBuf, int bufsize);
+
+#endif
|
|
|
@@ -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;
+}
+
|
|
@@ -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 |
|
|
@@ -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
|
|
@@ -0,0 +1,9 @@ + ; shellext: Declares the module parameters for the DLL.
+
+LIBRARY TORTOISEHGSHELL
+DESCRIPTION 'Shell Extensions for TortoiseHg'
+
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+
|
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
|
@@ -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 Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
|
@@ -0,0 +1,9 @@ + #ifndef _DIRSTATE_H
+#define _DIRSTATE_H
+
+#include <string>
+
+int HgQueryDirstate(
+ const std::string& path, const char& filterStatus, char& outStatus);
+
+#endif
|
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
Loading...