[PATCH 0 of 2] Fix Windows shellext 0x5c problem of Japanese shift-jis and Chinese(Taiwanese) big5.

24 views
Skip to first unread message

Toshi MARUYAMA

unread,
Sep 1, 2010, 10:20:50 AM9/1/10
to thg...@googlegroups.com

Toshi MARUYAMA

unread,
Sep 1, 2010, 10:20:52 AM9/1/10
to thg...@googlegroups.com
# HG changeset patch
# User Toshi MARUYAMA <marut...@gmail.com>
# Date 1283350110 -32400
# Node ID c56bb020d0d5f33c0fdfd7326aaca6e49ced88c3
# Parent aaea8a88dec973ad0b6e814bae16d7805e84b615
OverlayServer: catch exception of os.listdir(path).

This exception raises in case of
fixutf8 extension enabled and folder name contains '0x5c'(backslash).

diff -r aaea8a88dec9 -r c56bb020d0d5 TortoiseHgOverlayServer.py
--- a/TortoiseHgOverlayServer.py Wed Sep 01 23:02:36 2010 +0900
+++ b/TortoiseHgOverlayServer.py Wed Sep 01 23:08:30 2010 +0900
@@ -203,11 +203,17 @@
for path in batch:
r = paths.find_root(path)
if r is None:
+ try:
for n in os.listdir(path):
r = paths.find_root(os.path.join(path, n))
if (r is not None):
roots.add(r)
notifypaths.add(r)
+ except Exception, e:
+ # This exception raises in case of
+ # fixutf8 extension enabled and folder name contains '0x5c'(backslash).
+ logger.msg('Failed listdir %s (%s)' % (path, str(e)))
+ pass
else:
roots.add(r);
notifypaths.add(path)

Toshi MARUYAMA

unread,
Sep 1, 2010, 10:20:51 AM9/1/10
to thg...@googlegroups.com
# HG changeset patch
# User Toshi MARUYAMA <marut...@gmail.com>
# Date 1283349756 -32400
# Node ID aaea8a88dec973ad0b6e814bae16d7805e84b615
# Parent 30b5e85be646d321a8b9e5f8d661e487dce7f69e
win32shellext: Unicode porting and context-menu disabled on special folders (e.g. start-menu)

Issue #1241.

Merge squashed following jobs.

* Marco Lizza's patches exclude tortoisehg_rev6547.patch (Msi.lib).
http://groups.google.com/group/thg-dev/browse_thread/thread/8580c791fe5b52b2

* Tinyfish's Unicode porting.
http://bitbucket.org/tinyfish/tortoisehg.winutf8/changeset/cdce65b00f1e

diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/CShellExtCMenu.cpp
--- a/win32/shellext/CShellExtCMenu.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/CShellExtCMenu.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -13,148 +13,159 @@
#include "Msi.h"

#include <map>
+#include <tchar.h>

#include "CShellExtCMenu.h"

+#define THG_FILENAME L"thg"
+#define HGTK_FILENAME L"hgtk"
+
+#define LISTFILE_OPT_ACP L" --listfile "
+#define LISTFILE_CP_ACP CP_ACP

struct MenuDescription
{
- std::string name;
+ std::wstring name;
std::wstring menuText;
std::wstring helpText;
- std::string iconName;
+ std::wstring iconName;
UINT idCmd;
};

+const std::wstring TortoiseHgMenuEntryString = L"TortoiseHg";
+
// According to http://msdn.microsoft.com/en-us/library/bb776094%28VS.85%29.aspx
// the help texts for the commands should be reasonably short (under 40 characters)

MenuDescription menuDescList[] =
{
- {"commit", L"Commit...",
+ {L"commit", L"Commit...",
L"Commit changes in repository",
- "menucommit.ico", 0},
- {"init", L"Create Repository Here",
+ L"menucommit.ico", 0},
+ {L"init", L"Create Repository Here",
L"Create a new repository",
- "menucreaterepos.ico", 0},
- {"clone", L"Clone...",
+ L"menucreaterepos.ico", 0},
+ {L"clone", L"Clone...",
L"Create clone here from source",
- "menuclone.ico", 0},
- {"status", L"View File Status",
+ L"menuclone.ico", 0},
+ {L"status", L"View File Status",
L"Repository status & changes",
- "menushowchanged.ico", 0},
- {"add", L"Add Files...",
+ L"menushowchanged.ico", 0},
+ {L"add", L"Add Files...",
L"Add files to version control",
- "menuadd.ico", 0},
- {"revert", L"Revert Files...",
+ L"menuadd.ico", 0},
+ {L"revert", L"Revert Files...",
L"Revert file changes",
- "menurevert.ico", 0},
- {"remove", L"Remove Files...",
+ L"menurevert.ico", 0},
+ {L"remove", L"Remove Files...",
L"Remove files from version control",
- "menudelete.ico", 0},
- {"rename", L"Rename File...",
+ L"menudelete.ico", 0},
+ {L"rename", L"Rename File...",
L"Rename file or directory",
- "general.ico", 0},
- {"workbench", L"Workbench",
+ L"general.ico", 0},
+ {L"workbench", L"Workbench",
L"View change history of repository",
- "menulog.ico", 0},
- {"log", L"Revision History",
+ L"menulog.ico", 0},
+ {L"log", L"Revision History",
L"View change history of selected files",
- "menulog.ico", 0},
- {"synch", L"Synchronize",
+ L"menulog.ico", 0},
+ {L"synch", L"Synchronize",
L"Synchronize with remote repository",
- "menusynch.ico", 0},
- {"serve", L"Web Server",
+ L"menusynch.ico", 0},
+ {L"serve", L"Web Server",
L"Start web server for this repository",
- "proxy.ico", 0},
- {"update", L"Update...",
+ L"proxy.ico", 0},
+ {L"update", L"Update...",
L"Update working directory",
- "menucheckout.ico", 0},
- {"thgstatus", L"Update Icons",
+ L"menucheckout.ico", 0},
+ {L"thgstatus", L"Update Icons",
L"Update icons for this repository",
- "refresh_overlays.ico", 0},
- {"userconf", L"Global Settings",
+ L"refresh_overlays.ico", 0},
+ {L"userconf", L"Global Settings",
L"Configure user wide settings",
- "settings_user.ico", 0},
- {"repoconf", L"Repository Settings",
+ L"settings_user.ico", 0},
+ {L"repoconf", L"Repository Settings",
L"Configure repository settings",
- "settings_repo.ico", 0},
- {"about", L"About TortoiseHg",
+ L"settings_repo.ico", 0},
+ {L"about", L"About TortoiseHg",
L"Show About Dialog",
- "menuabout.ico", 0},
- {"vdiff", L"Visual Diff",
+ L"menuabout.ico", 0},
+ {L"vdiff", L"Visual Diff",
L"View changes using GUI diff tool",
- "TortoiseMerge.ico", 0},
- {"hgignore", L"Edit Ignore Filter",
+ L"TortoiseMerge.ico", 0},
+ {L"hgignore", L"Edit Ignore Filter",
L"Edit repository ignore filter",
- "ignore.ico", 0},
- {"guess", L"Guess Renames",
+ L"ignore.ico", 0},
+ {L"guess", L"Guess Renames",
L"Detect renames and copies",
- "detect_rename.ico", 0},
- {"grep", L"Search History",
+ L"detect_rename.ico", 0},
+ {L"grep", L"Search History",
L"Search file revisions for patterns",
- "menurepobrowse.ico", 0},
- {"forget", L"Forget Files...",
+ L"menurepobrowse.ico", 0},
+ {L"forget", L"Forget Files...",
L"Remove files from version control",
- "menudelete.ico", 0},
- {"shellconf", L"Explorer Extension Settings",
+ L"menudelete.ico", 0},
+ {L"shellconf", L"Explorer Extension Settings",
L"Configure Explorer extension",
- "settings_repo.ico", 0},
+ L"settings_repo.ico", 0},
+ {L"tortoisehg", TortoiseHgMenuEntryString,
+ L"Tortoise Hg",
+ L"hg.ico", 0},

/* Add new items here */

// template
- //{"", L"", L"", ".ico", 0},
+ //{L"", L"", L"", ".ico", 0},
};

-const char* const RepoNoFilesMenu =
- "commit status vdiff sep"
- " add revert rename forget remove sep"
- " workbench update grep sep"
- " synch serve clone init thgstatus sep"
- " hgignore guess sep"
- " shellconf repoconf userconf sep"
- " about"
+const wchar_t* const RepoNoFilesMenu =
+ L"commit status vdiff sep"
+ L" add revert rename forget remove sep"
+ L" workbench update grep sep"
+ L" synch serve clone init thgstatus sep"
+ L" hgignore guess sep"
+ L" shellconf repoconf userconf sep"
+ L" about"
;

-const char* const RepoFilesMenu =
- "commit status vdiff sep"
- " add revert rename forget remove sep"
- " log sep"
- " about"
+const wchar_t* const RepoFilesMenu =
+ L"commit status vdiff sep"
+ L" add revert rename forget remove sep"
+ L" log sep"
+ L" about"
;

-const char* const NoRepoMenu =
- "clone init shellconf userconf thgstatus sep"
- " about"
+const wchar_t* const NoRepoMenu =
+ L"clone init shellconf userconf thgstatus sep"
+ L" about"
;


-typedef std::map<std::string, MenuDescription> MenuDescriptionMap;
+typedef std::map<std::wstring, MenuDescription> MenuDescriptionMap;
typedef std::map<UINT, MenuDescription> MenuIdCmdMap;

MenuDescriptionMap MenuDescMap;
MenuIdCmdMap MenuIdMap;


-void AddMenuList(UINT idCmd, const std::string& name)
+void AddMenuList(UINT idCmd, const std::wstring& name)
{
- TDEBUG_TRACE("AddMenuList: idCmd = " << idCmd << " name = " << name);
+ TDEBUG_TRACEW(L"AddMenuList: idCmd = " << idCmd << L" name = " << name);
MenuIdMap[idCmd] = MenuDescMap[name];
}


void GetCMenuTranslation(
- const std::string& lang,
- const std::string& name,
+ const std::wstring& lang,
+ const std::wstring& name,
std::wstring& menuText,
std::wstring& helpText
)
{
std::wstring subkey = L"Software\\TortoiseHg\\CMenu\\";
- subkey += _WCSTR(lang.c_str());
+ subkey += lang;
subkey += L"\\";
- subkey += _WCSTR(name.c_str());
+ subkey += name;

TDEBUG_TRACEW(L"GetCMenuTranslation: " << subkey);

@@ -184,8 +195,8 @@
{
if (MenuDescMap.empty())
{
- std::string lang;
- GetRegistryConfig("CMenuLang", lang);
+ std::wstring lang;
+ GetRegistryConfig(L"CMenuLang", lang);

std::size_t sz = sizeof(menuDescList) / sizeof(MenuDescription);
for (std::size_t i = 0; i < sz; i++)
@@ -194,11 +205,11 @@

if (md.name.size() == 0)
{
- TDEBUG_TRACE("**** InitMenuMaps: ignoring entry with empty name");
+ TDEBUG_TRACEW(L"**** InitMenuMaps: ignoring entry with empty name");
break;
}

- TDEBUG_TRACE("InitMenuMaps: adding " << md.name);
+ TDEBUG_TRACEW(L"InitMenuMaps: adding " << md.name);

// Look for translation of menu and help text
if (lang.size())
@@ -214,7 +225,7 @@

void InsertMenuItemWithIcon1(
HMENU hMenu, UINT indexMenu, UINT idCmd,
- const std::wstring& menuText, const std::string& iconName)
+ const std::wstring& menuText, const std::wstring& iconName)
{
// MFT_STRING is obsolete and should not be used (replaced by MIIM_STRING
// from Win2K onward)
@@ -236,7 +247,7 @@
}
else
{
- TDEBUG_TRACE(" ***** InsertMenuItemWithIcon1: can't find " + iconName);
+ TDEBUG_TRACEW(L" ***** InsertMenuItemWithIcon1: can't find " + iconName);
}
}
else
@@ -250,7 +261,7 @@
}
else
{
- TDEBUG_TRACE(" ***** InsertMenuItemWithIcon1: can't find " + iconName);
+ TDEBUG_TRACEW(L" ***** InsertMenuItemWithIcon1: can't find " + iconName);
}
}
InsertMenuItemW(hMenu, indexMenu, TRUE, &mi);
@@ -262,7 +273,7 @@

void InsertSubMenuItemWithIcon2(
HMENU hMenu, HMENU hSubMenu, UINT indexMenu, UINT idCmd,
- const std::wstring& menuText, const std::string& iconName)
+ const std::wstring& menuText, const std::wstring& iconName)
{
// MFT_STRING is obsolete and should not be used (replaced by MIIM_STRING
// from Win2K onward)
@@ -285,7 +296,7 @@
}
else
{
- TDEBUG_TRACE(" ***** InsertSubMenuItemWithIcon2: can't find " + iconName);
+ TDEBUG_TRACEW(L" ***** InsertSubMenuItemWithIcon2: can't find " + iconName);
}
}
else
@@ -299,25 +310,25 @@
}
else
{
- TDEBUG_TRACE(" ***** InsertSubMenuItemWithIcon2: can't find " + iconName);
+ TDEBUG_TRACEW(L" ***** InsertSubMenuItemWithIcon2: can't find " + iconName);
}
}

InsertMenuItemW(hMenu, indexMenu, TRUE, &mi);

TDEBUG_TRACEW(
- L"InsertMenuItemWithIcon2(\"" << menuText << L"\") finished");
+ L"InsertSubMenuItemWithIcon2(\"" << menuText << L"\") finished");
}


void InsertMenuItemByName(
- HMENU hMenu, const std::string& name, UINT indexMenu,
+ HMENU hMenu, const std::wstring& name, UINT indexMenu,
UINT idCmd, UINT idCmdFirst, const std::wstring& prefix)
{
MenuDescriptionMap::iterator iter = MenuDescMap.find(name);
if (iter == MenuDescMap.end())
{
- TDEBUG_TRACE("***** InsertMenuItemByName: can't find menu info for " << name);
+ TDEBUG_TRACEW(L"***** InsertMenuItemByName: can't find menu info for " << name);
return;
}

@@ -327,8 +338,23 @@
hMenu, indexMenu, idCmd, prefix + md.menuText, md.iconName);
}

+void InsertSubMenuItemByName(
+ HMENU hMenu, HMENU hSubMenu, const std::wstring& name, UINT indexMenu,
+ UINT idCmd, UINT idCmdFirst)
+{
+ MenuDescriptionMap::iterator iter = MenuDescMap.find(name);
+ if (iter == MenuDescMap.end())
+ {
+ TDEBUG_TRACEW(L"***** InsertSubMenuItemByName: can't find menu info for " << name);
+ return;
+ }

-const std::wstring TortoiseHgMenuEntryString = L"TortoiseHg";
+ MenuDescription md = iter->second;
+ AddMenuList(idCmd - idCmdFirst, name);
+ InsertSubMenuItemWithIcon2(hMenu, hSubMenu, indexMenu, idCmd,
+ md.menuText, md.iconName);
+}
+

int HasTortoiseMenu(HMENU hMenu, bool& hasmenu)
// returns -1 on error, 0 otherwise
@@ -338,7 +364,7 @@
const int count = ::GetMenuItemCount(hMenu);
if (count == -1)
{
- TDEBUG_TRACE("***** HasTortoiseMenu: GetMenuItemCount returned -1");
+ TDEBUG_TRACEW(L"***** HasTortoiseMenu: GetMenuItemCount returned -1");
return -1;
}

@@ -352,7 +378,7 @@
mii.fMask = MIIM_STRING;
BOOL res = ::GetMenuItemInfoW(hMenu, i, true, &mii);
if (res == 0) {
- TDEBUG_TRACE("HasTortoiseMenu: "
+ TDEBUG_TRACEW(L"HasTortoiseMenu: "
<< "first GetMenuItemInfo returned 0");
continue;
}
@@ -371,7 +397,7 @@
++mii.cch; // size of buffer is one more than length of string
res = ::GetMenuItemInfoW(hMenu, i, true, &mii);
if (res == 0) {
- TDEBUG_TRACE("HasTortoiseMenu: "
+ TDEBUG_TRACEW(L"HasTortoiseMenu: "
<< "second GetMenuItemInfo returned 0");
continue;
}
@@ -382,24 +408,73 @@

if (menuitemtext == TortoiseHgMenuEntryString)
{
- TDEBUG_TRACE("HasTortoiseMenu: FOUND TortoiseHg menu entry");
+ TDEBUG_TRACEW(L"HasTortoiseMenu: FOUND TortoiseHg menu entry");
hasmenu = true;
return 0;
}
}

- TDEBUG_TRACE("HasTortoiseMenu: TortoiseHg menu entry NOT found");
+ TDEBUG_TRACEW(L"HasTortoiseMenu: TortoiseHg menu entry NOT found");
return 0;
}

#define ResultFromShort(i) ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, 0, (USHORT)(i)))

+bool IsSpecialFolder(const std::wstring &folder)
+{
+ static int pCSIDL[] =
+ {
+ CSIDL_BITBUCKET,
+ CSIDL_CDBURN_AREA,
+ CSIDL_COMMON_STARTMENU,
+ CSIDL_COMPUTERSNEARME,
+ CSIDL_CONNECTIONS,
+ CSIDL_CONTROLS,
+ CSIDL_COOKIES,
+ CSIDL_FONTS,
+ CSIDL_HISTORY,
+ CSIDL_INTERNET,
+ CSIDL_INTERNET_CACHE,
+ CSIDL_NETHOOD,
+ CSIDL_NETWORK,
+ CSIDL_PRINTERS,
+ CSIDL_PRINTHOOD,
+ CSIDL_RECENT,
+ CSIDL_SENDTO,
+ CSIDL_STARTMENU,
+ 0
+ };
+
+ TDEBUG_TRACEW(L"IsSpecialFolder");
+ for (int i = 0; pCSIDL[i] != 0; i++)
+ {
+ LPITEMIDLIST pIDL = NULL;
+ if (SHGetSpecialFolderLocation(NULL, pCSIDL[i], &pIDL) != S_OK)
+ continue;
+
+ TCHAR tszPath[MAX_PATH + 1] = { _T('\0') };
+ BOOL bResult = SHGetPathFromIDList(pIDL, tszPath);
+
+ CoTaskMemFree(pIDL);
+
+ if ((bResult == FALSE) || (tszPath[0] == _T('\0')))
+ continue;
+
+ if (_tcsicmp(tszPath, folder.c_str())==0)
+ {
+ TDEBUG_TRACEW(L" folder '" << folder << L"' is special");
+ return true;
+ }
+ }
+ return false;
+}
+
// IContextMenu
STDMETHODIMP
CShellExtCMenu::QueryContextMenu(
HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
- TDEBUG_TRACE("CShellExtCMenu::QueryContextMenu");
+ TDEBUG_TRACEW(L"CShellExtCMenu::QueryContextMenu");

UINT idCmd = idCmdFirst;
BOOL bAppendItems = TRUE;
@@ -419,26 +494,26 @@
bool hasthgmenu = false;
if (HasTortoiseMenu(hMenu, hasthgmenu) == 0 && hasthgmenu)
{
- TDEBUG_TRACE("CShellExtCMenu::QueryContextMenu: "
+ TDEBUG_TRACEW(L"CShellExtCMenu::QueryContextMenu: "
<< "TortoiseHg menu entry already in menu -> skipping");
return S_OK;
}

InitMenuMaps();

- typedef std::vector<std::string> entriesT;
+ typedef std::vector<std::wstring> entriesT;
typedef entriesT::const_iterator entriesIter;

- std::string promoted_string = "commit,workbench"; // default value if key not found
- GetRegistryConfig("PromotedItems", promoted_string);
+ std::wstring promoted_string = L"commit,workbench"; // default value if key not found
+ GetRegistryConfig(L"PromotedItems", promoted_string);

entriesT promoted;
- Tokenize(promoted_string, promoted, ",");
+ Tokenize(promoted_string, promoted, L",");

// Select menu to show
bool fileMenu = myFiles.size() > 0;
bool isHgrepo = false;
- std::string cwd;
+ std::wstring cwd;
if (!myFolder.empty())
{
cwd = myFolder;
@@ -448,10 +523,16 @@
cwd = IsDirectory(myFiles[0])? myFiles[0] : DirName(myFiles[0]);
}

+ if (IsSpecialFolder(cwd)) {
+ // disable context menu if in a special folder
+ TDEBUG_TRACEW(L" shell-extension not available in this folder");
+ return S_OK;
+ }
+
if (!cwd.empty())
{
// check if target directory is a Mercurial repository
- std::string root = GetHgRepoRoot(cwd);
+ std::wstring root = GetHgRepoRoot(cwd);
isHgrepo = !root.empty();
if (myFiles.size() == 1 && root == myFiles[0])
{
@@ -461,13 +542,13 @@
}
}

- TDEBUG_TRACE(
- "CShellExtCMenu::QueryContextMenu: isHgrepo = "
- << isHgrepo << ", fileMenu = " << fileMenu
+ TDEBUG_TRACEW(
+ L"CShellExtCMenu::QueryContextMenu: isHgrepo = "
+ << isHgrepo << L", fileMenu = " << fileMenu
);

/* We have three menu types: files-selected, no-files-selected, no-repo */
- const char* entries_string = 0;
+ const wchar_t* entries_string = 0;
if (isHgrepo)
if (fileMenu)
entries_string = RepoFilesMenu;
@@ -480,11 +561,11 @@
InsertMenu(hMenu, indexMenu++, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);

entriesT entries;
- Tokenize(entries_string, entries, " ");
+ Tokenize(entries_string, entries, L" ");

for (entriesIter i = entries.begin(); i != entries.end(); i++)
{
- std::string name = *i;
+ std::wstring name = *i;
if (contains(promoted, name))
{
InsertMenuItemByName(
@@ -501,8 +582,8 @@
bool isSeparator = true;
for (entriesIter i = entries.begin(); i != entries.end(); i++)
{
- std::string name = *i;
- if (name == "sep")
+ std::wstring name = *i;
+ if (name == L"sep")
{
if (!isSeparator)
{
@@ -542,9 +623,8 @@
}
}

- TDEBUG_TRACE(" CShellExtCMenu::QueryContextMenu: adding main THG menu");
- InsertSubMenuItemWithIcon2(hMenu, hSubMenu, indexMenu++, idCmd++,
- TortoiseHgMenuEntryString, "hg.ico");
+ TDEBUG_TRACEW(L" CShellExtCMenu::QueryContextMenu: adding main THG menu");
+ InsertSubMenuItemByName(hMenu, hSubMenu, L"tortoisehg", indexMenu++, idCmd++, idCmdFirst);

InsertMenu(hMenu, indexMenu++, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);

@@ -570,13 +650,13 @@
STDMETHODIMP
CShellExtCMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
- TDEBUG_TRACE("CShellExtCMenu::InvokeCommand");
+ TDEBUG_TRACEW(L"CShellExtCMenu::InvokeCommand");

HRESULT hr = E_INVALIDARG;
if (!HIWORD(lpcmi->lpVerb))
{
UINT idCmd = LOWORD(lpcmi->lpVerb);
- TDEBUG_TRACE("CShellExtCMenu::InvokeCommand: idCmd = " << idCmd);
+ TDEBUG_TRACEW(L"CShellExtCMenu::InvokeCommand: idCmd = " << idCmd);
MenuIdCmdMap::iterator iter = MenuIdMap.find(idCmd);
if (iter != MenuIdMap.end())
{
@@ -585,8 +665,8 @@
}
else
{
- TDEBUG_TRACE(
- "***** CShellExtCMenu::InvokeCommand: action not found for idCmd "
+ TDEBUG_TRACEW(
+ L"***** CShellExtCMenu::InvokeCommand: action not found for idCmd "
<< idCmd
);
}
@@ -607,38 +687,38 @@
const char* psz = "";
const wchar_t* pszw = 0;

- std::string sflags = "?";
+ std::wstring sflags = L"?";
switch (uFlags)
{
case GCS_HELPTEXTW:
- sflags = "GCS_HELPTEXTW"; break;
+ sflags = L"GCS_HELPTEXTW"; break;
case GCS_HELPTEXTA:
- sflags = "GCS_HELPTEXTA"; break;
+ sflags = L"GCS_HELPTEXTA"; break;
case GCS_VALIDATEW:
- sflags = "GCS_VALIDATEW"; break;
+ sflags = L"GCS_VALIDATEW"; break;
case GCS_VALIDATEA:
- sflags = "GCS_VALIDATEA"; break;
+ sflags = L"GCS_VALIDATEA"; break;
case GCS_VERBW:
- sflags = "GCS_VERBW"; break;
+ sflags = L"GCS_VERBW"; break;
case GCS_VERBA:
- sflags = "GCS_VERBA"; break;
+ sflags = L"GCS_VERBA"; break;
}

- TDEBUG_TRACE(
- "CShellExtCMenu::GetCommandString: idCmd = " << idCmd
- << ", uFlags = " << uFlags << " (" << sflags << ")"
- << ", cchMax = " << cchMax
+ TDEBUG_TRACEW(
+ L"CShellExtCMenu::GetCommandString: idCmd = " << idCmd
+ << L", uFlags = " << uFlags << L" (" << sflags << L")"
+ << L", cchMax = " << cchMax
);

MenuIdCmdMap::iterator iter = MenuIdMap.find(static_cast<UINT>(idCmd));
if (iter == MenuIdMap.end())
{
- TDEBUG_TRACE("***** CShellExtCMenu::GetCommandString: idCmd not found");
+ TDEBUG_TRACEW(L"***** CShellExtCMenu::GetCommandString: idCmd not found");
}
else
{
- TDEBUG_TRACE(
- "CShellExtCMenu::GetCommandString: name = \"" << iter->second.name << "\"");
+ TDEBUG_TRACEW(
+ L"CShellExtCMenu::GetCommandString: name = \"" << iter->second.name << L"\"");

if (uFlags == GCS_HELPTEXTW)
{
@@ -648,10 +728,10 @@
size_t size = iter->second.helpText.size();
if (size >= 40)
{
- TDEBUG_TRACE(
- "***** CShellExtCMenu::GetCommandString: warning:"
- << " length of help text is " << size
- << ", which is not reasonably short (<40)");
+ TDEBUG_TRACEW(
+ L"***** CShellExtCMenu::GetCommandString: warning:"
+ << L" length of help text is " << size
+ << L", which is not reasonably short (<40)");
}
}
else if (uFlags == GCS_HELPTEXTA)
@@ -678,7 +758,7 @@

if (cchMax < 1)
{
- TDEBUG_TRACE("CShellExtCMenu::GetCommandString: cchMax = "
+ TDEBUG_TRACEW(L"CShellExtCMenu::GetCommandString: cchMax = "
<< cchMax << " (is <1)");
return res;
}
@@ -688,7 +768,8 @@
if (uFlags & GCS_UNICODE)
{
wchar_t* const dest = reinterpret_cast<wchar_t*>(pszName);
- const wchar_t* const src = pszw ? pszw : _WCSTR(psz);
+ std::wstring ws_src = MultibyteToWide(psz, CP_ACP, 0) ;
+ const wchar_t* const src = pszw ? pszw : ws_src.c_str();

wcsncpy(dest, src, cchMax-1);
*(dest + cchMax-1) = 0;
@@ -705,15 +786,15 @@

size = strlen(psz);

- TDEBUG_TRACE("CShellExtCMenu::GetCommandString: res = " << int(res)
+ TDEBUG_TRACEW(L"CShellExtCMenu::GetCommandString: res = " << int(res)
<< ", pszName = \"" << psz << "\"");
}

if (size > cchMax-1)
{
- TDEBUG_TRACE(
- "***** CShellExtCMenu::GetCommandString: string was truncated: size = "
- << size << ", cchMax = " << cchMax);
+ TDEBUG_TRACEW(
+ L"***** CShellExtCMenu::GetCommandString: string was truncated: size = "
+ << size << L", cchMax = " << cchMax);
}

return res;
@@ -779,33 +860,39 @@
}


-void CShellExtCMenu::RunDialog(const std::string &cmd)
+void CShellExtCMenu::RunDialog(const std::wstring &cmd)
{
- std::string dir = GetTHgProgRoot();
+ std::wstring dir = GetTHgProgRoot();
if (dir.empty())
{
- TDEBUG_TRACE("RunDialog: THG root is empty");
+ TDEBUG_TRACEW(L"RunDialog: THG root is empty");
return;
}
- std::string hgcmd = dir + "\\thg.exe";

- WIN32_FIND_DATAA data;
- HANDLE hfind = FindFirstFileA(hgcmd.c_str(), &data);
+ std::wstring hgcmd ;
+ hgcmd = dir + L"\\" + THG_FILENAME + L".exe";
+
+ WIN32_FIND_DATA data;
+ HANDLE hfind = FindFirstFile(hgcmd.c_str(), &data);
if (hfind == INVALID_HANDLE_VALUE)
{
- hgcmd = dir + "\\hgtk.exe";
- hfind = FindFirstFileA(hgcmd.c_str(), &data);
+ hgcmd = dir + L"\\" + HGTK_FILENAME + L".exe";
+ hfind = FindFirstFile(hgcmd.c_str(), &data);
if (hfind == INVALID_HANDLE_VALUE)
- hgcmd = dir + "\\thg.cmd";
+ {
+ hgcmd = dir + L"\\" + THG_FILENAME + L".cmd";
+ }
else
FindClose(hfind);
}
else
+ {
FindClose(hfind);
+ }

- hgcmd = Quote(hgcmd) + " --nofork " + cmd;
+ hgcmd = Quote(hgcmd) + L" --nofork " + cmd;

- std::string cwd;
+ std::wstring cwd;
if (!myFolder.empty())
{
cwd = myFolder;
@@ -816,52 +903,56 @@
}
else
{
- TDEBUG_TRACE("***** RunDialog: can't get cwd");
+ TDEBUG_TRACEW(L"***** RunDialog: can't get cwd");
return;
}

+ UINT CodePage = LISTFILE_CP_ACP ;
+ std::wstring listfile_opt = LISTFILE_OPT_ACP ;

if (!myFiles.empty())
{
- const std::string tempfile = GetTemporaryFile();
+ const std::wstring tempfile = GetTemporaryFile();
+
if (tempfile.empty())
{
- TDEBUG_TRACE("***** RunDialog: error: GetTemporaryFile returned empty string");
+ TDEBUG_TRACEW(L"***** RunDialog: error: GetTemporaryFile returned empty string");
return;
}

- TDEBUG_TRACE("RunDialog: temp file = " << tempfile);
- HANDLE tempfileHandle = CreateFileA(
+ TDEBUG_TRACEW(L"RunDialog: temp file = " << tempfile);
+ HANDLE tempfileHandle = CreateFile(
tempfile.c_str(), GENERIC_WRITE,
FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0
);

if (tempfileHandle == INVALID_HANDLE_VALUE)
{
- TDEBUG_TRACE("***** RunDialog: error: failed to create file " << tempfile);
+ TDEBUG_TRACEW(L"***** RunDialog: error: failed to create file " << tempfile);
return;
}

- typedef std::vector<std::string>::size_type ST;
+ typedef std::vector<std::wstring>::size_type ST;
for (ST i = 0; i < myFiles.size(); i++)
{
DWORD dwWritten;
- TDEBUG_TRACE("RunDialog: temp file adding " << myFiles[i]);
+ std::string str_file = WideToMultibyte(myFiles[i], CodePage);
+ TDEBUG_TRACEW(L"RunDialog: temp file adding " << myFiles[i]);
WriteFile(
- tempfileHandle, myFiles[i].c_str(),
- static_cast<DWORD>(myFiles[i].size()), &dwWritten, 0
+ tempfileHandle, str_file.c_str(),
+ static_cast<DWORD>(str_file.size()), &dwWritten, 0
);
- WriteFile(tempfileHandle, "\n", 1, &dwWritten, 0);
+ WriteFile(tempfileHandle, "\n", sizeof(char), &dwWritten, 0);
}
CloseHandle(tempfileHandle);
- hgcmd += " --listfile " + Quote(tempfile);
+ hgcmd += listfile_opt + Quote(tempfile);
}

- if (cmd == "thgstatus")
+ if (cmd == L"thgstatus")
{
if (Thgstatus::remove(cwd) != 0)
{
- std::string p = dir + "\\TortoiseHgOverlayServer.exe";
+ std::wstring p = dir + L"\\TortoiseHgOverlayServer.exe";
LaunchCommand(Quote(p), cwd);
}
InitStatus::check();
@@ -878,27 +969,27 @@
{
TCHAR name[MAX_PATH+1];

- TDEBUG_TRACE("CShellExtCMenu::Initialize");
+ TDEBUG_TRACEW(L"CShellExtCMenu::Initialize");

// get installed MSI product id (for debugging purposes for now)
#ifdef _M_X64
- const char* shellexid = "{59FD2A49-BA62-40CC-B155-D11DB11EE611}";
+ const wchar_t* shellexid = L"{59FD2A49-BA62-40CC-B155-D11DB11EE611}";
#else
- const char* shellexid = "{1126CF42-3994-428B-A746-464E1BC680F3}";
+ const wchar_t* shellexid = L"{1126CF42-3994-428B-A746-464E1BC680F3}";
#endif
- std::vector<char> product_id(50, 0);
- UINT msires = ::MsiGetProductCodeA(shellexid, &product_id[0]);
- TDEBUG_TRACE("MSI shellexid: " << shellexid);
- TDEBUG_TRACE("MSI msires: " << msires);
- TDEBUG_TRACE("MSI installed product id: " << &product_id[0]);
+ std::vector<wchar_t> product_id(50, 0);
+ UINT msires = ::MsiGetProductCode(shellexid, &product_id[0]);
+ TDEBUG_TRACEW(L"MSI shellexid: " << shellexid);
+ TDEBUG_TRACEW(L"MSI msires: " << msires);
+ TDEBUG_TRACEW(L"MSI installed product id: " << &product_id[0]);

TDEBUG_TRACEW(
L"---- TortoiseHg shell extension version "
<< ThgVersion::get() << L"----"
);

- TDEBUG_TRACE(" pIDFolder: " << pIDFolder);
- TDEBUG_TRACE(" pDataObj: " << pDataObj);
+ TDEBUG_TRACEW(L" pIDFolder: " << pIDFolder);
+ TDEBUG_TRACEW(L" pDataObj: " << pDataObj);

myFolder.clear();
myFiles.clear();
@@ -907,56 +998,54 @@
{
FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stg = { TYMED_HGLOBAL };
- if (SUCCEEDED(pDataObj->GetData(&fmt, &stg)) && stg.hGlobal)
+ if (SUCCEEDED(pDataObj->GetData(&fmt, &stg)))
{
HDROP hDrop = (HDROP) GlobalLock(stg.hGlobal);

if (hDrop)
{
UINT uNumFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
- TDEBUG_TRACE(" hDrop uNumFiles = " << uNumFiles);
+ TDEBUG_TRACEW(L" hDrop uNumFiles = " << uNumFiles);
for (UINT i = 0; i < uNumFiles; ++i) {
if (DragQueryFile(hDrop, i, name, MAX_PATH) > 0)
{
- TDEBUG_TRACE(" DragQueryFile [" << i << "] = " << name);
+ TDEBUG_TRACEW(L" DragQueryFile [" << i << "] = " << name);
myFiles.push_back(name);
}
}
}
- else
- {
- TDEBUG_TRACE(" hDrop is NULL ");
- }

GlobalUnlock(stg.hGlobal);
- if (stg.pUnkForRelease)
+ ReleaseStgMedium(&stg);
+
+ if (hDrop == NULL)
{
- IUnknown* relInterface = (IUnknown*) stg.pUnkForRelease;
- relInterface->Release();
+ TDEBUG_TRACEW(L" hDrop is NULL ");
+ return E_INVALIDARG;
}
}
else
{
- TDEBUG_TRACE(" pDataObj->GetData failed");
+ TDEBUG_TRACEW(L" pDataObj->GetData failed");
+ return E_INVALIDARG;
}
}

// if a directory background
if (pIDFolder)
{
- SHGetPathFromIDList(pIDFolder, name);
- TDEBUG_TRACE(" Folder " << name);
- myFolder = name;
+ if (SHGetPathFromIDList(pIDFolder, name) == TRUE)
+ {
+ TDEBUG_TRACEW(L" Folder " << name);
+ myFolder = name;
+ }
+ else
+ {
+ TDEBUG_TRACEW(L" SHGetPathFromIDList() failed");
+ return E_INVALIDARG;
+ }
}
-
- // disable context menu if neither the folder nor the files
- // have been found
- if (myFolder.empty() && myFiles.empty()) {
- TDEBUG_TRACE(" shell extension not available on this object");
- return E_FAIL;
- } else {
- return S_OK;
- }
+ return S_OK;
}


diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/CShellExtCMenu.h
--- a/win32/shellext/CShellExtCMenu.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/CShellExtCMenu.h Wed Sep 01 23:02:36 2010 +0900
@@ -9,11 +9,11 @@
{
ULONG m_cRef;

- LPTSTR* m_ppszFileUserClickedOn; // [MAX_PATH]
- std::vector<std::string> myFiles;
- std::string myFolder;
+ LPWSTR* m_ppszFileUserClickedOn; // [MAX_PATH]
+ std::vector<std::wstring> myFiles;
+ std::wstring myFolder;

- void RunDialog(const std::string&);
+ void RunDialog(const std::wstring&);

public:
explicit CShellExtCMenu(char dummy);
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/CShellExtOverlay.cpp
--- a/win32/shellext/CShellExtOverlay.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/CShellExtOverlay.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -12,7 +12,7 @@
STDMETHODIMP CShellExtOverlay::GetOverlayInfo(
LPWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags)
{
- TDEBUG_TRACE("CShellExtOverlay::GetOverlayInfo: myTortoiseClass = " << myTortoiseClass);
+ TDEBUG_TRACEW(L"CShellExtOverlay::GetOverlayInfo: myTortoiseClass = " << myTortoiseClass);
// icons are determined by TortoiseOverlays shim
*pIndex = 0;
*pdwFlags = 0;
@@ -32,8 +32,8 @@
{
ThgCriticalSection cs(CShellExt::GetCriticalSection());

- std::string cval;
- if (GetRegistryConfig("EnableOverlays", cval) != 0 && cval == "0")
+ std::wstring cval;
+ if (GetRegistryConfig(L"EnableOverlays", cval) != 0 && cval == L"0")
return S_FALSE;

// This overlay handler processes all filenames in lowercase, so that a path
@@ -43,13 +43,13 @@
std::wstring lowerpath(pwszPath);
::CharLowerW(const_cast<wchar_t*>(lowerpath.c_str()));

- std::string path = WideToMultibyte(lowerpath.c_str());
+ std::wstring path = lowerpath; //WideToMultibyte(lowerpath.c_str());

- if (GetRegistryConfig("LocalDisksOnly", cval) != 0 && cval != "0"
+ if (GetRegistryConfig(L"LocalDisksOnly", cval) != 0 && cval != L"0"
&& PathIsNetworkPath(path.c_str()))
return S_FALSE;

- char filterStatus = 0;
+ wchar_t filterStatus = 0;
if (myTortoiseClass == 'A')
filterStatus = 'A';

diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/Directory.cpp
--- a/win32/shellext/Directory.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/Directory.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -15,16 +15,16 @@
// 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 <time.h>

-#include "stdafx.h"
-
#include "Directory.h"
#include "Winstat.h"


Directory::Directory(
- Directory* p, const std::string& n, const std::string& basepath
+ Directory* p, const std::wstring& n, const std::wstring& basepath
):
parent_(p), name_(n)
{
@@ -33,7 +33,7 @@
else if (basepath.empty())
path_ = n;
else
- path_ = basepath + '/' + n;
+ path_ = basepath + L'/' + n;
}


@@ -46,13 +46,13 @@
}


-int splitbase(const std::string& n, std::string& base, std::string& rest)
+int splitbase(const std::wstring& n, std::wstring& base, std::wstring& rest)
{
if (n.empty())
return 0;

- size_t x = n.find_first_of ('/');
- if (x == std::string::npos)
+ size_t x = n.find_first_of (L'/');
+ if (x == std::wstring::npos)
{
base.clear();
rest = n;
@@ -69,19 +69,19 @@
}


-int Directory::add(const std::string& n_in, Direntry& e)
+int Directory::add(const std::wstring& n_in, Direntry& e)
{
- std::string base;
- std::string rest;
+ std::wstring base;
+ std::wstring rest;

- std::string n = n_in;
+ std::wstring n = n_in;
Directory* cur = this;

for (;;)
{

if (!splitbase(n, base, rest)) {
- TDEBUG_TRACE("Directory(" << path() << ")::add(" << n_in
+ TDEBUG_TRACEW(L"Directory(" << path() << ")::add(" << n_in
<< "): splitbase returned 0");
return 0;
}
@@ -115,12 +115,12 @@
}


-const Direntry* Directory::get(const std::string& n_in) const
+const Direntry* Directory::get(const std::wstring& n_in) const
{
- std::string base;
- std::string rest;
+ std::wstring base;
+ std::wstring rest;

- std::string n = n_in;
+ std::wstring n = n_in;
const Directory* cur = this;

for (;;)
@@ -129,7 +129,7 @@

if (!splitbase(n, base, rest))
{
- TDEBUG_TRACE("Directory(" << path() << ")::get("
+ TDEBUG_TRACEW(L"Directory(" << path() << ")::get("
<< n_in << "): splitbase returned 0");
return 0;
}
@@ -161,12 +161,12 @@
}


-Directory* Directory::getdir(const std::string& n_in)
+Directory* Directory::getdir(const std::wstring& n_in)
{
- std::string base;
- std::string rest;
+ std::wstring base;
+ std::wstring rest;

- std::string n = n_in;
+ std::wstring n = n_in;
const Directory* cur = this;

for (;;)
@@ -175,13 +175,13 @@

if (!splitbase(n, base, rest))
{
- TDEBUG_TRACE("Directory(" << path() << ")::getdir("
+ TDEBUG_TRACEW(L"Directory(" << path() << ")::getdir("
<< n_in << "): splitbase returned 0");
return 0;
}

const bool leaf = base.empty();
- const std::string& searchstr = (leaf ? n : base);
+ const std::wstring& searchstr = (leaf ? n : base);

for (DirsT::const_iterator i = cur->subdirs_.begin();
i != cur->subdirs_.end(); ++i)
@@ -208,32 +208,32 @@
const Directory* d = *i;
if (!d)
{
- TDEBUG_TRACE("Directory(" << path() << ")::print: error: d is 0");
+ TDEBUG_TRACEW(L"Directory(" << path() << ")::print: error: d is 0");
return;
}
d->print();
}

- std::string base = path();
+ std::wstring base = path();

time_t t;
- std::string s;
- char* ctime_res = 0;
+ std::wstring s;
+ wchar_t* ctime_res = 0;

for (FilesT::const_iterator i = files_.begin(); i != files_.end(); ++i)
{
- std::string p = (!base.empty() ? base + "/" + i->name : i->name);
+ std::wstring p = (!base.empty() ? base + L"/" + i->name : i->name);
t = i->mtime;
- ctime_res = ctime(&t);
+ ctime_res = _wctime(&t);
if (ctime_res) {
s = ctime_res;
s.resize(s.size() - 1); // strip ending '\n'
}
else {
- s = "unset";
+ s = L"unset";
}
- printf(
- "%c %6o %10u %-24s %s\n",
+ wprintf(
+ L"%c %6o %10u %-24s %s\n",
i->state, i->mode, i->size, s.c_str(), p.c_str()
);
}
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/Directory.h
--- a/win32/shellext/Directory.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/Directory.h Wed Sep 01 23:02:36 2010 +0900
@@ -30,22 +30,22 @@
typedef std::vector<Direntry> FilesT;

Directory* const parent_;
- const std::string name_;
- std::string path_;
+ const std::wstring name_;
+ std::wstring path_;

DirsT subdirs_;
FilesT files_;

public:
- Directory(Directory* p, const std::string& n, const std::string& basepath);
+ Directory(Directory* p, const std::wstring& n, const std::wstring& basepath);
~Directory();

- const std::string& path() const { return path_; }
+ const std::wstring& path() const { return path_; }

- int add(const std::string& relpath, Direntry& e);
+ int add(const std::wstring& relpath, Direntry& e);

- const Direntry* get(const std::string& relpath) const;
- Directory* getdir(const std::string& n);
+ const Direntry* get(const std::wstring& relpath) const;
+ Directory* getdir(const std::wstring& n);

void print() const;
};
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/DirectoryStatus.cpp
--- a/win32/shellext/DirectoryStatus.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/DirectoryStatus.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -19,15 +19,15 @@
#include "DirectoryStatus.h"
#include "Thgstatus.h"
#include "TortoiseUtils.h"
+#include "StringUtils.h"

-
-char DirectoryStatus::status(const std::string& relpath_) const
+char DirectoryStatus::status(const std::wstring& relpath_) const
{
char res = 'C';
bool added = false;
bool modified = false;

- const std::string relpath = relpath_ + '/';
+ const std::wstring relpath = relpath_ + L'/';

for (V::const_iterator i = v_.begin(); i != v_.end(); ++i)
{
@@ -56,18 +56,23 @@
}


-int DirectoryStatus::read(const std::string& hgroot, const std::string& cwd)
+int DirectoryStatus::read(const std::wstring& hgroot, const std::wstring& cwd)
{
+ TDEBUG_TRACEW (
+ L"DirectoryStatus::read: hgroot: '" << hgroot << L"'"
+ << L" cwd: '" << L"'"
+ ) ;
+
v_.clear();
noicons_ = false;

- std::string p = hgroot + "\\.hg\\thgstatus";
+ std::wstring p = hgroot + L"\\.hg\\thgstatus";

FILE *f = fopenReadRenameAllowed(p.c_str());
if (!f)
{
- TDEBUG_TRACE("DirectoryStatus::read: can't open '" << p << "'");
- std::string p = (cwd.size() < hgroot.size() ? hgroot : cwd);
+ TDEBUG_TRACEW(L"DirectoryStatus::read: can't open '" << p << L"'");
+ std::wstring p = (cwd.size() < hgroot.size() ? hgroot : cwd);
Thgstatus::update(p);
return 0;
}
@@ -82,15 +87,15 @@
for (;;)
{
vline.clear();
- char t;
+ char c;

for (;;)
{
- if (fread(&t, sizeof(t), 1, f) != 1)
+ if (fread(&c, sizeof(c), 1, f) != 1)
goto close;
- if (t == '\n')
+ if (c == '\n')
break;
- vline.push_back(t);
+ vline.push_back(c);
if (vline.size() > 1000)
{
res = 0;
@@ -112,15 +117,17 @@

e.status_ = line[0];

- std::string path;
+ std::string path;
+ std::wstring wpath;
if (line.size() > 1)
{
path = line.c_str() + 1;
- ::CharLower(const_cast<char*>(path.c_str()));
+ wpath = ThgMultibyteToWide ( path ) ;
+ ::CharLower(const_cast<wchar_t*>(wpath.c_str()));
}
- path.push_back('/');
+ wpath.push_back(L'/');

- e.path_ = path;
+ e.path_ = wpath;

v_.push_back(e);
}
@@ -128,7 +135,7 @@
close:
fclose(f);

- TDEBUG_TRACE("DirectoryStatus::read(" << hgroot << "): done. "
+ TDEBUG_TRACEW(L"DirectoryStatus::read(" << hgroot << "): done. "
<< v_.size() << " entries read. noicons_ = " << noicons_ );

return res;
@@ -137,7 +144,7 @@

struct CacheEntry
{
- std::string hgroot_;
+ std::wstring hgroot_;
DirectoryStatus ds_;
bool readfailed_;
unsigned tickcount_;
@@ -147,7 +154,7 @@


DirectoryStatus* DirectoryStatus::get(
- const std::string& hgroot, const std::string& cwd)
+ const std::wstring& hgroot, const std::wstring& cwd)
{
static CacheEntry ce;

diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/DirectoryStatus.h
--- a/win32/shellext/DirectoryStatus.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/DirectoryStatus.h Wed Sep 01 23:02:36 2010 +0900
@@ -22,7 +22,7 @@
{
struct E
{
- std::string path_;
+ std::wstring path_;
char status_;

E(): status_(0) {}
@@ -36,10 +36,10 @@
DirectoryStatus(): noicons_(false) {}

static DirectoryStatus* get(
- const std::string& hgroot, const std::string& cwd);
- char status(const std::string& relpath) const;
+ const std::wstring& hgroot, const std::wstring& cwd);
+ char status(const std::wstring& relpath) const;
bool noicons() const { return noicons_; }

private:
- int read(const std::string& hgroot, const std::string& cwd);
+ int read(const std::wstring& hgroot, const std::wstring& cwd);
};
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/Direntry.cpp
--- a/win32/shellext/Direntry.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/Direntry.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -42,8 +42,6 @@
fread(&relpath[0], sizeof(char), length, f);
relpath[length] = 0;

- ::CharLowerBuff(&relpath[0], length);
-
return 1;
}

diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/Direntry.h
--- a/win32/shellext/Direntry.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/Direntry.h Wed Sep 01 23:02:36 2010 +0900
@@ -35,7 +35,7 @@
unsigned size;
unsigned mtime;

- std::string name;
+ std::wstring name;

int read(FILE* f, std::vector<char>& relpath);
char status(const Winstat& stat) const;
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/Dirstatecache.cpp
--- a/win32/shellext/Dirstatecache.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/Dirstatecache.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -31,7 +31,7 @@


Dirstate* Dirstatecache::get(
- const std::string& hgroot, const std::string& cwd, bool& unset)
+ const std::wstring& hgroot, const std::wstring& cwd, bool& unset)
{
unset = false;

@@ -45,7 +45,7 @@
}

Winstat64 stat;
- std::string path = hgroot + "\\.hg\\dirstate";
+ std::wstring path = hgroot + L"\\.hg\\dirstate";

unsigned tc = GetTickCount();
bool new_stat = false;
@@ -54,15 +54,15 @@
{
if (stat.lstat(path.c_str()) != 0)
{
- TDEBUG_TRACE("Dirstatecache::get: lstat(" << path <<") failed");
+ TDEBUG_TRACEW(L"Dirstatecache::get: lstat(" << path <<") failed");
return 0;
}
- TDEBUG_TRACE("Dirstatecache::get: lstat(" << path <<") ok ");
+ TDEBUG_TRACEW(L"Dirstatecache::get: lstat(" << path <<") ok ");
new_stat = true;

if (cache().size() >= 10)
{
- TDEBUG_TRACE("Dirstatecache::get: dropping "
+ TDEBUG_TRACEW(L"Dirstatecache::get: dropping "
<< cache().back().hgroot);
delete cache().back().dstate;
cache().back().dstate = 0;
@@ -80,15 +80,15 @@
{
if (0 != stat.lstat(path.c_str()))
{
- TDEBUG_TRACE("Dirstatecache::get: lstat(" << path <<") failed");
- TDEBUG_TRACE("Dirstatecache::get: dropping " << iter->hgroot);
+ TDEBUG_TRACEW(L"Dirstatecache::get: lstat(" << path <<") failed");
+ TDEBUG_TRACEW(L"Dirstatecache::get: dropping " << iter->hgroot);
delete iter->dstate;
iter->dstate = 0;
cache().erase(iter);
return 0;
}
iter->tickcount = tc;
- TDEBUG_TRACE("Dirstatecache::get: lstat(" << path <<") ok ");
+ TDEBUG_TRACEW(L"Dirstatecache::get: lstat(" << path <<") ok ");
new_stat = true;
}

@@ -105,11 +105,11 @@
return iter->dstate;
}

- TDEBUG_TRACE("Dirstatecache::get: refreshing " << hgroot);
+ TDEBUG_TRACEW(L"Dirstatecache::get: refreshing " << hgroot);
}
else
{
- TDEBUG_TRACE("Dirstatecache::get: reading " << hgroot);
+ TDEBUG_TRACEW(L"Dirstatecache::get: reading " << hgroot);
}

unset = false;
@@ -123,13 +123,13 @@
{
if (iter->unset)
{
- TDEBUG_TRACE(
- "Dirstatecache::get: **** old and new have unset entries");
+ TDEBUG_TRACEW(
+ L"Dirstatecache::get: **** old and new have unset entries");
request_thgstatus_update = false;
}
else
{
- TDEBUG_TRACE("Dirstatecache::get: new has unset entries");
+ TDEBUG_TRACEW(L"Dirstatecache::get: new has unset entries");
}
}

@@ -139,7 +139,7 @@
iter->dstate = ds.release();

unsigned delta = tc1 - tc0;
- TDEBUG_TRACE("Dirstatecache::get: read done in " << delta << " ticks, "
+ TDEBUG_TRACEW(L"Dirstatecache::get: read done in " << delta << " ticks, "
<< cache().size() << " repos in cache");

iter->dstate_mtime = stat.mtime;
@@ -147,19 +147,19 @@

if (request_thgstatus_update)
{
- TDEBUG_TRACE("Dirstatecache::get: calling Thgstatus::update");
+ TDEBUG_TRACEW(L"Dirstatecache::get: calling Thgstatus::update");
Thgstatus::update(cwd);
}
else
{
- TDEBUG_TRACE("Dirstatecache::get: omitting Thgstatus::update");
+ TDEBUG_TRACEW(L"Dirstatecache::get: omitting Thgstatus::update");
}

return iter->dstate;
}


-void Dirstatecache::invalidate(const std::string& hgroot)
+void Dirstatecache::invalidate(const std::wstring& hgroot)
{
typedef std::list<E>::iterator Iter;

@@ -173,7 +173,7 @@
delete i->dstate;
i->dstate = 0;
cache().erase(i);
- TDEBUG_TRACE("Dirstatecache::invalidate(" << hgroot << ")");
+ TDEBUG_TRACEW(L"Dirstatecache::invalidate(" << hgroot << ")");
break;
}
}
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/Dirstatecache.h
--- a/win32/shellext/Dirstatecache.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/Dirstatecache.h Wed Sep 01 23:02:36 2010 +0900
@@ -31,7 +31,7 @@
__int64 dstate_mtime;
__int64 dstate_size;

- std::string hgroot;
+ std::wstring hgroot;
unsigned tickcount;
bool unset;

@@ -48,8 +48,8 @@

public:
static Dirstate* get(
- const std::string& hgroot, const std::string& cwd, bool& unset);
- static void invalidate(const std::string& hgroot);
+ const std::wstring& hgroot, const std::wstring& cwd, bool& unset);
+ static void invalidate(const std::wstring& hgroot);
};

#endif
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/IconBitmapUtils.cpp
--- a/win32/shellext/IconBitmapUtils.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/IconBitmapUtils.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -110,7 +110,7 @@

if (pfnBeginBufferedPaint == NULL || pfnEndBufferedPaint == NULL || pfnGetBufferedPaintBits == NULL)
{
- TDEBUG_TRACE(" IconBitmapUtils::IconToBitmapPARGB32: Theme functions not found, returns NULL");
+ TDEBUG_TRACEW(L" IconBitmapUtils::IconToBitmapPARGB32: Theme functions not found, returns NULL");
return NULL;
}

diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/InitStatus.cpp
--- a/win32/shellext/InitStatus.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/InitStatus.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -27,34 +27,34 @@
}


-void InitStatus::add(std::string& s, const char* missing)
+void InitStatus::add(std::wstring& s, const wchar_t* missing)
{
if (!s.empty())
- s += ", ";
+ s += L", ";
s += missing;
}


-std::string InitStatus::check()
+std::wstring InitStatus::check()
{
const InitStatus& self = inst();
- std::string missing;
+ std::wstring missing;

if (self.unchanged_ == 0)
- add(missing, "unchanged");
+ add(missing, L"unchanged");
if (self.added_ == 0)
- add(missing, "added");
+ add(missing, L"added");
if (self.modified_ == 0)
- add(missing, "modified");
+ add(missing, L"modified");
if (self.notinrepo_ == 0)
- add(missing, "notinrepo");
+ add(missing, L"notinrepo");

if (missing.empty())
- return "";
+ return L"";

- std::string reason = "uninitialized handlers: " + missing;
+ std::wstring reason = L"uninitialized handlers: " + missing;
Thgstatus::error(reason);
- std::string res = "InitStatus: error: " + reason;
- TDEBUG_TRACE("***** " << res);
+ std::wstring res = L"InitStatus: error: " + reason;
+ TDEBUG_TRACEW(L"***** " << res);
return res;
}
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/InitStatus.h
--- a/win32/shellext/InitStatus.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/InitStatus.h Wed Sep 01 23:02:36 2010 +0900
@@ -25,11 +25,11 @@
int notinrepo_;

static InitStatus& inst();
- static std::string check();
+ static std::wstring check();

private:
InitStatus()
: unchanged_(0), added_(0), modified_(0), notinrepo_(0) {}

- static void add(std::string& s, const char* missing);
+ static void add(std::wstring& s, const wchar_t* missing);
};
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/Makefile.nmake
--- a/win32/shellext/Makefile.nmake Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/Makefile.nmake Wed Sep 01 23:02:36 2010 +0900
@@ -4,6 +4,7 @@
Directory.obj \
Winstat.obj \
RegistryConfig.obj \
+ StringUtils.obj \
ThgDebug.obj

OBJECTS_THGSGELL = $(OBJECTS_DIRSTATE) \
@@ -26,6 +27,14 @@

OBJECTS_TERMINATE = Thgstatus.obj \
RegistryConfig.obj \
+ StringUtils.obj \
+ ThgDebug.obj
+
+OBJECTS_STRINGUTILS_TEST = \
+ StringUtils.test.obj \
+ StringUtils.obj \
+ TortoiseUtils.obj \
+ RegistryConfig.obj \
ThgDebug.obj

LIBS = shlwapi.lib gdiplus.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Msi.lib
@@ -34,7 +43,7 @@

# /MT = statically linked runtime libraries /MD = dynamically linked
# THG_EXTRA_CPPFLAGS is taken from environment (may be undefined)
-CPPFLAGS = /nologo /Ox /W2 /EHsc /MT /DAPPMAIN /DTHG_DEBUG $(THG_EXTRA_CPPFLAGS)
+CPPFLAGS = /D "_UNICODE" /D "UNICODE" /nologo /Ox /W2 /EHsc /MT /DAPPMAIN /DTHG_DEBUG $(THG_EXTRA_CPPFLAGS)
BASE_LDFLAGS = /nologo /INCREMENTAL:NO /MANIFEST $(LIBS)
LDFLAGS_THGSHELL = $(BASE_LDFLAGS) /DLL /DEF:$(DEFFILE)
LDFLAGS_DIRSTATE = $(BASE_LDFLAGS) /SUBSYSTEM:CONSOLE
@@ -65,3 +74,8 @@
$(TERMINATE_TARGET): terminate.obj $(OBJECTS_TERMINATE)
link /OUT:$@ $(LDFLAGS_TERMINATE) $**
mt -nologo -manifest $@.manifest -outputresource:"$@;#1"
+
+stringutils.exe: $(OBJECTS_STRINGUTILS_TEST)
+ link /OUT:$@ $(BASE_LDFLAGS) /SUBSYSTEM:CONSOLE $**
+ mt -nologo -manifest $@.manifest -outputresource:"$@;#1"
+
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/QueryDirstate.cpp
--- a/win32/shellext/QueryDirstate.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/QueryDirstate.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -31,28 +31,28 @@
class QueryState
{
public:
- std::string path;
+ std::wstring path;
bool isdir;
- std::string basedir;
- std::string hgroot;
+ std::wstring basedir;
+ std::wstring hgroot;

- char status;
+ wchar_t status;
unsigned tickcount;

QueryState(): isdir(false), status('0'), tickcount(0) {}
};


-bool hasHgDir(char cls, const std::string& path, unsigned& ticks)
+bool hasHgDir(wchar_t cls, const std::wstring& path, unsigned& ticks)
{
ticks = 0;

bool res = false;

- if (path.empty() || path == "\\")
+ if (path.empty() || path == L"\\")
return res;

- const std::string p = path + "\\.hg";
+ const std::wstring p = path + L"\\.hg";

if (::PathIsUNCServerShare(p.c_str()))
return res;
@@ -66,9 +66,9 @@
if (ticks > 5 /* ms */)
{
// trace slower PathIsDirectory calls (untypical on local discs)
- TDEBUG_TRACE(
- "[" << cls << "] hasHgDir: PathIsDirectory(\"" << p << "\")" <<
- " -> " << res << ", in " << ticks << " ticks"
+ TDEBUG_TRACEW(
+ L"[" << cls << L"] hasHgDir: PathIsDirectory(\"" << p << L"\")" <<
+ L" -> " << res << L", in " << ticks << L" ticks"
);
}

@@ -76,14 +76,14 @@
}


-int findHgRoot(char cls, QueryState& cur, QueryState& last, bool outdated)
+int findHgRoot(wchar_t cls, QueryState& cur, QueryState& last, bool outdated)
{
- std::string dp = "["; dp += cls; dp += "] findHgRoot";
+ std::wstring dp = L"["; dp += cls; dp += L"] findHgRoot";

{
- std::string p = cur.path;
- p.push_back('\\');
- if (p.find("\\.hg\\") != std::string::npos)
+ std::wstring p = cur.path;
+ p.push_back(L'\\');
+ if (p.find(L"\\.hg\\") != std::wstring::npos)
{
// ignore files and dirs named '.hg'
last = cur;
@@ -93,7 +93,7 @@

if (!outdated && !last.hgroot.empty()
&& cur.path.size() >= last.hgroot.size()
- && StartsWith(cur.path, last.hgroot + "\\"))
+ && StartsWith(cur.path, last.hgroot + L"\\"))
{
cur.hgroot = last.hgroot;
return 1;
@@ -117,7 +117,7 @@
if (has_hg)
{
cur.hgroot = cur.path;
- TDEBUG_TRACE(dp << "(" << cur.path << "): hgroot = cur.path");
+ TDEBUG_TRACEW(dp << L"(" << cur.path << L"): hgroot = cur.path");
return 1;
}
}
@@ -130,12 +130,12 @@
return 1;
}

- for (std::string p = cur.basedir;;)
+ for (std::wstring p = cur.basedir;;)
{
bool has_hg = hasHgDir(cls, p, ticks);
if (ticks > 5000 /* ms */)
{
- const std::string reason = "ignoring slow \"" + p + "\"";
+ const std::wstring reason = L"ignoring slow \"" + p + L"\"";
Thgstatus::error(reason);
file_access_is_unacceptably_slow = true;
goto exit;
@@ -144,13 +144,13 @@
if (has_hg)
{
cur.hgroot = p;
- TDEBUG_TRACE(
- dp << "(" << cur.path << "): hgroot = '" << cur.hgroot
- << "' (found repo)"
+ TDEBUG_TRACEW(
+ dp << L"(" << cur.path << L"): hgroot = '" << cur.hgroot
+ << L"' (found repo)"
);
return 1;
}
- std::string p2 = DirName(p);
+ std::wstring p2 = DirName(p);
if (p2.size() == p.size())
break;
p.swap(p2);
@@ -159,13 +159,13 @@
exit:
if (file_access_is_unacceptably_slow)
{
- TDEBUG_TRACE(
- "******" << dp << "(" << cur.path << "): ignored, "
- << "call took too long (" << ticks << " ticks)");
+ TDEBUG_TRACEW(
+ L"******" << dp << L"(" << cur.path << L"): ignored, "
+ << L"call took too long (" << ticks << L" ticks)");
}
else
{
- TDEBUG_TRACE(dp << "(" << cur.path << "): NO repo found");
+ TDEBUG_TRACEW(dp << L"(" << cur.path << L"): NO repo found");
}
last = cur;
return 0;
@@ -173,9 +173,9 @@


int get_relpath(
- const std::string& hgroot,
- const std::string& path,
- std::string& res
+ const std::wstring& hgroot,
+ const std::wstring& path,
+ std::wstring& res
)
{
size_t offset = hgroot.size();
@@ -185,10 +185,10 @@
if (offset > path.size())
return 0;

- if (path[offset] == '\\')
+ if (path[offset] == L'\\')
offset++;
-
- const char* relpathptr = path.c_str() + offset;
+
+ const wchar_t* relpathptr = path.c_str() + offset;

res = relpathptr;
return 1;
@@ -197,12 +197,12 @@

int HgQueryDirstate(
const char cls,
- const std::string& path,
- const char& filterStatus,
+ const std::wstring& path,
+ const wchar_t& filterStatus,
char& outStatus
)
{
- std::string dp = "["; dp += cls; dp += "] HgQueryDirstate: ";
+ std::wstring dp = L"["; dp += cls; dp += L"] HgQueryDirstate: ";

static QueryState last;

@@ -241,16 +241,16 @@
return 0;
}

- if (path[offset] == '\\')
+ if (path[offset] == L'\\')
offset++;
- const char* relpathptr = path.c_str() + offset;
+ const wchar_t* relpathptr = path.c_str() + offset;

- std::string relpath = relpathptr;
+ std::wstring relpath = relpathptr;

for (size_t i = 0; i < relpath.size(); ++i)
{
- if (relpath[i] == '\\')
- relpath[i] = '/';
+ if (relpath[i] == L'\\')
+ relpath[i] = L'/';
}

DirectoryStatus* pdirsta = DirectoryStatus::get(cur.hgroot, cur.basedir);
@@ -274,9 +274,9 @@
Dirstate* pds = Dirstatecache::get(cur.hgroot, cur.basedir, unset);
if (!pds)
{
- TDEBUG_TRACE(
- dp << "Dirstatecache::get(" << cur.hgroot
- << ") returns no Dirstate"
+ TDEBUG_TRACEW(
+ dp << L"Dirstatecache::get(" << cur.hgroot
+ << L") returns no Dirstate"
);
last = cur;
return 0;
@@ -285,7 +285,7 @@
Winstat stat;
if (0 != stat.lstat(path.c_str()))
{
- TDEBUG_TRACE(dp << "lstat(" << path << ") failed");
+ TDEBUG_TRACEW(dp << L"lstat(" << path << L") failed");
last = cur;
return 0;
}
@@ -328,17 +328,17 @@

if (outStatus == 'M')
{
- std::string relbase;
+ std::wstring relbase;
if (pdirsta && get_relpath(cur.hgroot, cur.basedir, relbase))
{
- TDEBUG_TRACE(dp << "relbase = '" << relbase << "'");
+ TDEBUG_TRACEW(dp << L"relbase = '" << relbase << L"'");

char basedir_status = pdirsta->status(relbase);
- TDEBUG_TRACE(dp << "basedir_status = " << basedir_status);
+ TDEBUG_TRACEW(dp << L"basedir_status = " << basedir_status);

if (basedir_status != 'M')
update = true;
- }
+ }
}
else if (outStatus == 'P')
{
@@ -353,12 +353,12 @@
lasttickcount = tc;
}

- TDEBUG_TRACE(dp << "outStatus is 'P'");
+ TDEBUG_TRACEW(dp << L"outStatus is 'P'");
}

if (update)
{
- TDEBUG_TRACE(dp << "calling Thgstatus::update");
+ TDEBUG_TRACEW(dp << L"calling Thgstatus::update");
Thgstatus::update(path);
}

diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/QueryDirstate.h
--- a/win32/shellext/QueryDirstate.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/QueryDirstate.h Wed Sep 01 23:02:36 2010 +0900
@@ -5,8 +5,8 @@

int HgQueryDirstate(
const char myClass,
- const std::string& path,
- const char& filterStatus,
+ const std::wstring& path,
+ const wchar_t& filterStatus,
char& outStatus
);

diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/RegistryConfig.cpp
--- a/win32/shellext/RegistryConfig.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/RegistryConfig.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -1,27 +1,27 @@
#include "stdafx.h"
#include "RegistryConfig.h"

-int GetRegistryConfig(const std::string& name, std::string& res)
+int GetRegistryConfig(const std::wstring& name, std::wstring& res)
{
- const char* const subkey = "Software\\TortoiseHg";
+ const wchar_t* const subkey = L"Software\\TortoiseHg";

HKEY hkey = 0;
- LONG rv = RegOpenKeyExA(
+ LONG rv = RegOpenKeyEx(
HKEY_CURRENT_USER, subkey, 0, KEY_READ, &hkey);

if (rv != ERROR_SUCCESS || hkey == 0)
return 0;

- BYTE Data[MAX_PATH] = "";
+ BYTE Data[MAX_PATH * 2] = {0};
DWORD cbData = MAX_PATH * sizeof(BYTE);

- rv = RegQueryValueExA(
+ rv = RegQueryValueEx(
hkey, name.c_str(), 0, 0, Data, &cbData);

int ret = 0;
if (rv == ERROR_SUCCESS)
{
- res = reinterpret_cast<const char*>(&Data);
+ res = reinterpret_cast<const wchar_t*>(&Data);
ret = 1;
}

diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/RegistryConfig.h
--- a/win32/shellext/RegistryConfig.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/RegistryConfig.h Wed Sep 01 23:02:36 2010 +0900
@@ -3,6 +3,6 @@

#include <string>

-int GetRegistryConfig(const std::string& name, std::string& res);
+int GetRegistryConfig(const std::wstring& name, std::wstring& res);

#endif
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/ShellExt.cpp
--- a/win32/shellext/ShellExt.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/ShellExt.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -43,14 +43,14 @@
{
if (dwReason == DLL_PROCESS_ATTACH)
{
- TDEBUG_TRACE("DllMain: DLL_PROCESS_ATTACH");
+ TDEBUG_TRACEW(L"DllMain: DLL_PROCESS_ATTACH");
g_hmodThisDll = hInstance;
::InitializeCriticalSection(&g_critical_section);
_LoadResources();
}
else if (dwReason == DLL_PROCESS_DETACH)
{
- TDEBUG_TRACE("DllMain: DLL_PROCESS_ATTACH");
+ TDEBUG_TRACEW(L"DllMain: DLL_PROCESS_ATTACH");
::DeleteCriticalSection(&g_critical_section);
_UnloadResources();
}
@@ -61,7 +61,7 @@

STDAPI DllCanUnloadNow(void)
{
- TDEBUG_TRACE("DllCanUnloadNow");
+ TDEBUG_TRACEW(L"DllCanUnloadNow");
return (g_cRefThisDll == 0 ? S_OK : S_FALSE);
}

@@ -76,11 +76,11 @@
::CoTaskMemFree(ptr);
}

- TDEBUG_TRACEW("DllGetClassObject clsid = " << clsid);
+ TDEBUG_TRACEW(L"DllGetClassObject clsid = " << clsid);

if (ppvOut == 0)
{
- TDEBUG_TRACE("**** DllGetClassObject: error: ppvOut is 0");
+ TDEBUG_TRACEW(L"**** DllGetClassObject: error: ppvOut is 0");
return E_POINTER;
}

@@ -92,34 +92,34 @@
if (clsid == CLSID_TortoiseHgCmenu)
{
FactCmenu *pcf = new FactCmenu(0);
- TDEBUG_TRACE("DllGetClassObject clsname = " << "CLSID_TortoiseHgCmenu");
+ TDEBUG_TRACEW(L"DllGetClassObject clsname = " << L"CLSID_TortoiseHgCmenu");
return pcf->QueryInterface(riid, ppvOut);
}
else if (clsid == CLSID_TortoiseHgNormal)
{
FactOvl *pcf = new FactOvl('C'); // clean
- TDEBUG_TRACE("DllGetClassObject clsname = " << "CLSID_TortoiseHgNormal");
+ TDEBUG_TRACEW(L"DllGetClassObject clsname = " << L"CLSID_TortoiseHgNormal");
++InitStatus::inst().unchanged_;
return pcf->QueryInterface(riid, ppvOut);
}
else if (clsid == CLSID_TortoiseHgAdded)
{
FactOvl *pcf = new FactOvl('A'); // added
- TDEBUG_TRACE("DllGetClassObject clsname = " << "CLSID_TortoiseHgAdded");
+ TDEBUG_TRACEW(L"DllGetClassObject clsname = " << L"CLSID_TortoiseHgAdded");
++InitStatus::inst().added_;
return pcf->QueryInterface(riid, ppvOut);
}
else if (clsid == CLSID_TortoiseHgModified)
{
FactOvl *pcf = new FactOvl('M'); // modified
- TDEBUG_TRACE("DllGetClassObject clsname = " << "CLSID_TortoiseHgModified");
+ TDEBUG_TRACEW(L"DllGetClassObject clsname = " << L"CLSID_TortoiseHgModified");
++InitStatus::inst().modified_;
return pcf->QueryInterface(riid, ppvOut);
}
else if (clsid == CLSID_TortoiseHgUnversioned)
{
FactOvl *pcf = new FactOvl('?'); // not in repo
- TDEBUG_TRACE("DllGetClassObject clsname = " << "CLSID_TortoiseHgUnversioned");
+ TDEBUG_TRACEW(L"DllGetClassObject clsname = " << L"CLSID_TortoiseHgUnversioned");
++InitStatus::inst().notinrepo_;
return pcf->QueryInterface(riid, ppvOut);
}
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/StringUtils.cpp
--- a/win32/shellext/StringUtils.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/StringUtils.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -15,15 +15,15 @@
// 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 "StringUtils.h"

#include <vector>

-
// Quotes a string
-std::string Quote(const std::string& str)
+std::wstring Quote(const std::wstring& str)
{
- std::string sResult = "\"" + str + "\"";
+ std::wstring sResult = L"\"" + str + L"\"";
return sResult;
}

@@ -37,7 +37,7 @@
NULL, 0, NULL, NULL
);

- std::vector<CHAR> narrow(ret + 1);
+ std::vector<char> narrow(ret + 1);

ret = WideCharToMultiByte(
CodePage, 0, wide.c_str(), static_cast<int>(wide.length()),
@@ -50,13 +50,15 @@


// Convert multibyte string to Unicode string
-std::wstring MultibyteToWide(const std::string& multibyte, UINT CodePage)
+std::wstring MultibyteToWide(const std::string& multibyte, UINT CodePage, DWORD dwFlags)
{
int ret = MultiByteToWideChar(
- CodePage, 0, multibyte.c_str(),
+ CodePage, dwFlags, multibyte.c_str(),
static_cast<int>(multibyte.length()), 0, 0
);

+ if ( ret == 0 ) { return L"" ; }
+
std::vector<wchar_t> wide(ret + 1);

ret = MultiByteToWideChar(
@@ -67,3 +69,40 @@

return &wide[0];
}
+
+// Convert multibyte string to Unicode string of .hg/dirstate and .hg/thgstatus
+std::wstring ThgMultibyteToWide (
+ const std::string& multibyte
+ , UINT CodePage
+ , bool FlagDebug
+ , bool FlagAssumeUtf8First
+ )
+{
+ std::wstring wc = L"" ;
+
+ if ( FlagAssumeUtf8First )
+ {
+ wc = MultibyteToWide(multibyte, CP_UTF8, MB_ERR_INVALID_CHARS);
+ if (FlagDebug)
+ {
+ if ( wc == L"" )
+ {
+ TDEBUG_TRACEW(L"hg file UTF-8 INVALID");
+ }
+ else
+ {
+ TDEBUG_TRACEW(L"hg file UTF-8: " << wc);
+ }
+ }
+ }
+ if ( wc == L"" )
+ {
+ wc = MultibyteToWide(multibyte, CodePage, 0);
+ if (FlagDebug)
+ {
+ TDEBUG_TRACEW(L"hg file CP" << CodePage << ": " << wc);
+ }
+ }
+ return wc;
+}
+
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/StringUtils.h
--- a/win32/shellext/StringUtils.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/StringUtils.h Wed Sep 01 23:02:36 2010 +0900
@@ -22,13 +22,26 @@
#include <windows.h>

// Quotes a string
-std::string Quote(const std::string& str);
+std::wstring Quote(const std::wstring& str);

// 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);
+// Convert multibyte string to Unicode string
+std::wstring MultibyteToWide(const std::string& multibyte, UINT CodePage, DWORD dwFlags);

+// Convert multibyte string to Unicode string of .hg/dirstate and .hg/thgstatus
+//
+// .hg/dirstate and .hg/thgstatus are written in multibyte.
+// If fixutf8 is enabled, these files are written in UTF-8.
+// Firstly we try to convert from UTF-8. If it successes, return Unicode.
+// If it failes, we try to convert from CP_ACP.
+//
+std::wstring ThgMultibyteToWide (
+ const std::string& multibyte
+ , UINT CodePage = CP_ACP
+ , bool FlagDebug = false
+ , bool FlagAssumeUtf8First = false
+ );

#endif
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/StringUtils.test.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/win32/shellext/StringUtils.test.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -0,0 +1,110 @@
+
+#include "stdafx.h"
+#include "StringUtils.h"
+
+/*
+ test for assuming utf-8.
+ */
+void test_ThgMultibyteToWide(UINT CodePage, bool CanCat, int start, int end, int length = 1)
+{
+ int c ;
+ int cnt_success = 0 ;
+ int cnt_fail = 0 ;
+ int cnt = 0;
+ std::string s_cat = "" ;
+ // for ( c = 0xC0 ; c <= 0xFF ; c++ )
+ for ( c = start ; c <= end ; c++ )
+ {
+ if ( c % 256 == 0 )
+ {
+ continue ;
+ }
+ cnt++ ;
+ char c1;
+ char c2;
+ std::string s2 ;
+ if ( c > 256 )
+ {
+ c1 = c / 256 ;
+ s2 += c1 ;
+ c2 = c % 256 ;
+ }
+ else
+ {
+ c2 = c ;
+ }
+ s2 += c2 ;
+ // printf("%s\n", s2.c_str());
+ s_cat += s2 ;
+ std::wstring w1;
+ w1 = ThgMultibyteToWide(s2,CodePage,true);
+ if ( w1 == L"" )
+ {
+ printf("test fails %d\n", c);
+ cnt_fail++ ;
+ continue ;
+ }
+ if ( w1.length() != length )
+ {
+ printf("test fails %x\n", c);
+ cnt_fail++ ;
+ continue ;
+ }
+ std::string u1;
+ u1 = WideToMultibyte(w1,CP_UTF8);
+ std::wstring w3;
+ w3 = ThgMultibyteToWide(u1,CodePage,true);
+ if ( w1 == w3 )
+ {
+ // printf("test successes %d\n", c);
+ // printf("test successes %d: %c\n", c, c);
+ cnt_success++ ;
+ }
+ else
+ {
+ printf("test fails %d\n", c);
+ cnt_fail++ ;
+ }
+ }
+ printf("tests success %d\n", cnt_success );
+ printf("tests fail %d\n", cnt_fail );
+
+ if ( CanCat )
+ {
+ std::wstring w2;
+ w2 = ThgMultibyteToWide(s_cat,CodePage,true);
+ if ( w2 == L"" )
+ {
+ printf("test fails\n");
+ return ;
+ }
+ std::string u2;
+ u2 = WideToMultibyte(w2,CP_UTF8);
+ std::wstring w4;
+ w4 = ThgMultibyteToWide(u2,CodePage,true);
+ if ( w2 == w4 )
+ {
+ printf("test successes\n");
+ }
+ else
+ {
+ printf("test fails\n");
+ }
+ }
+}
+
+int main(int argc, wchar_t *argv[])
+{
+ test_ThgMultibyteToWide(1252,true,0x01, 0xFF);
+ test_ThgMultibyteToWide(1252,true,0x0101, 0xFFFF,2);
+ test_ThgMultibyteToWide(932, true,0x01, 0xFF);
+ test_ThgMultibyteToWide(932, true,0x8140, 0x84BE);
+ test_ThgMultibyteToWide(932, true,0x889F, 0x9872);
+ test_ThgMultibyteToWide(932, true,0x989F, 0x9FFC);
+ test_ThgMultibyteToWide(932, true,0xE040, 0xEAA4);
+ test_ThgMultibyteToWide(932, true,0x8740, 0x879C);
+ test_ThgMultibyteToWide(932, true,0xED40, 0xEEFC);
+ test_ThgMultibyteToWide(932, true,0xFA40, 0xFC4B);
+ return 0;
+}
+
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/ThgDebug.cpp
--- a/win32/shellext/ThgDebug.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/ThgDebug.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -6,13 +6,14 @@
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.

+#include "stdafx.h"
#include "ThgDebug.h"
#include "RegistryConfig.h"

bool ThgDebug::regDebugShellExt()
{
- std::string val;
- return GetRegistryConfig("DebugShellExt", val) != 0 && val == "1";
+ std::wstring val;
+ return GetRegistryConfig(L"DebugShellExt", val) != 0 && val == L"1";
}

bool ThgDebug::enabled()
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/ThgVersion.cpp
--- a/win32/shellext/ThgVersion.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/ThgVersion.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -1,3 +1,4 @@
+#include "stdafx.h"
#include "ThgVersion.h"
#include "parentid.h"

diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/Thgstatus.cpp
--- a/win32/shellext/Thgstatus.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/Thgstatus.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -17,38 +17,59 @@
#include "stdafx.h"

#include "Thgstatus.h"
+#include "StringUtils.h"

#include <vector>


-std::string GetPipeName()
+std::wstring GetPipeName()
{
DWORD size = 260;
- std::vector<char> buf(size);
- if (!::GetUserNameA(&buf[0], &size))
- return "";
- std::string res = "\\\\.\\pipe\\TortoiseHgRpcServer-bc0c27107423-";
+ std::vector<wchar_t> buf(size);
+ if (!::GetUserName(&buf[0], &size))
+ return L"";
+ std::wstring res = L"\\\\.\\pipe\\TortoiseHgRpcServer-bc0c27107423-";
res += &buf[0];
return res;
}

+#define PIPE_W 0

-int Thgstatus::SendRequest(const std::string& request)
+int Thgstatus::SendRequest(const std::wstring& request)
{
- static const std::string pname = GetPipeName();
+ static const std::wstring pname = GetPipeName();
+ static const std::string pname_a = WideToMultibyte(pname,CP_ACP);
+ std::string request_a;

if (pname.empty())
+ {
return 0;
+ }
+
+ if (! PIPE_W)
+ {
+ request_a = WideToMultibyte(request,CP_ACP);
+ }

BOOL fSuccess;
DWORD cbRead;

- TDEBUG_TRACE("Thgstatus::update: sending '" << request << "' to " << pname);
+ TDEBUG_TRACEW(L"Thgstatus::update: sending '" << request << "' to " << pname);

- fSuccess = ::CallNamedPipeA(
- pname.c_str(), (void*)request.c_str(), request.size(), 0, 0, &cbRead,
- NMPWAIT_NOWAIT
- );
+ if (PIPE_W)
+ {
+ fSuccess = ::CallNamedPipe(
+ pname.c_str(), (void*)request.c_str(), sizeof(wchar_t) * request.size(), 0, 0, &cbRead,
+ NMPWAIT_NOWAIT
+ );
+ }
+ else
+ {
+ fSuccess = ::CallNamedPipeA(
+ pname_a.c_str(), (void*)request_a.c_str(), request_a.size(), 0, 0, &cbRead,
+ NMPWAIT_NOWAIT
+ );
+ }

DWORD err = GetLastError();
if (fSuccess || err == ERROR_MORE_DATA || err == ERROR_PIPE_NOT_CONNECTED)
@@ -57,14 +78,14 @@
}
else if (err == ERROR_PIPE_BUSY)
{
- TDEBUG_TRACE("Thgstatus::update: CallNamedPipeA failed. "
- "ERROR_PIPE_BUSY");
+ TDEBUG_TRACEW(L"Thgstatus::update: CallNamedPipe failed. "
+ L"ERROR_PIPE_BUSY");
return -1;
}
else
{
- TDEBUG_TRACE("Thgstatus::update: CallNamedPipeA failed ("
- << err << ")");
+ TDEBUG_TRACEW(L"Thgstatus::update: CallNamedPipe failed ("
+ << err << L")");
return -1;
}
}
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/Thgstatus.h
--- a/win32/shellext/Thgstatus.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/Thgstatus.h Wed Sep 01 23:02:36 2010 +0900
@@ -21,20 +21,20 @@

class Thgstatus
{
- static int SendRequest(const std::string& request);
+ static int SendRequest(const std::wstring& request);

public:
- static int update(const std::string& path) {
- return SendRequest("update|" + path);
+ static int update(const std::wstring& path) {
+ return SendRequest(L"update|" + path);
}
- static int remove(const std::string& path) {
- return SendRequest("remove|" + path);
+ static int remove(const std::wstring& path) {
+ return SendRequest(L"remove|" + path);
}
- static int error(const std::string& text) {
- return SendRequest("error|" + text);
+ static int error(const std::wstring& text) {
+ return SendRequest(L"error|" + text);
}
static int terminate() {
- return SendRequest("terminate|");
+ return SendRequest(L"terminate|");
}
};

diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/TortoiseIconBitmap.cpp
--- a/win32/shellext/TortoiseIconBitmap.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/TortoiseIconBitmap.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -6,10 +6,10 @@
#include "IconBitmapUtils.h"


-HBITMAP GetTortoiseIconBitmap(const std::string& iconname)
+HBITMAP GetTortoiseIconBitmap(const std::wstring& iconname)
{
IconBitmapUtils bmpUtils;
- typedef std::map<std::string, HBITMAP> BitmapCacheT;
+ typedef std::map<std::wstring, HBITMAP> BitmapCacheT;
static BitmapCacheT bmpcache_;

BitmapCacheT::const_iterator i = bmpcache_.find(iconname);
@@ -18,7 +18,7 @@

if (bmpcache_.size() > 200)
{
- TDEBUG_TRACE("**** GetTortoiseIconBitmap: error: too many bitmaps in cache");
+ TDEBUG_TRACEW(L"**** GetTortoiseIconBitmap: error: too many bitmaps in cache");
return 0;
}

@@ -29,15 +29,15 @@
HBITMAP hBmp = bmpUtils.IconToBitmapPARGB32(hIcon);
if (!hBmp)
{
- TDEBUG_TRACE("**** GetTortoiseIconBitmap: error: something wrong in bmpUtils.ConvertToPARGB32(hIcon)");
+ TDEBUG_TRACEW(L"**** GetTortoiseIconBitmap: error: something wrong in bmpUtils.ConvertToPARGB32(hIcon)");
return 0;
}

bmpcache_[iconname] = hBmp;

- TDEBUG_TRACE(
- "GetTortoiseIconBitmap: added '" << iconname << "' to bmpcache_"
- " (" << bmpcache_.size() << " bitmaps in cache)"
+ TDEBUG_TRACEW(
+ L"GetTortoiseIconBitmap: added '" << iconname << L"' to bmpcache_"
+ L" (" << bmpcache_.size() << L" bitmaps in cache)"
);

return hBmp;
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/TortoiseIconBitmap.h
--- a/win32/shellext/TortoiseIconBitmap.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/TortoiseIconBitmap.h Wed Sep 01 23:02:36 2010 +0900
@@ -4,6 +4,6 @@
#include <windows.h>
#include <string>

-HBITMAP GetTortoiseIconBitmap(const std::string& iconname);
+HBITMAP GetTortoiseIconBitmap(const std::wstring& iconname);

#endif
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/TortoiseUtils.cpp
--- a/win32/shellext/TortoiseUtils.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/TortoiseUtils.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -10,38 +10,15 @@

#include "shlwapi.h"

-
-LPWSTR hf_mbtowc(LPWSTR lpw, LPCSTR lpa, int nChars)
+std::wstring GetTHgProgRoot()
{
- assert(lpa != NULL);
- assert(lpw != NULL);
-
- lpw[0] = '\0';
- MultiByteToWideChar(CP_ACP, 0, lpa, -1, lpw, nChars);
- return lpw;
-}
-
-
-LPSTR hf_wctomb(LPSTR lpa, LPCWSTR lpw, int nChars)
-{
- assert(lpw != NULL);
- assert(lpa != NULL);
-
- lpa[0] = '\0';
- WideCharToMultiByte(CP_ACP, 0, lpw, -1, lpa, nChars, NULL, NULL);
- return lpa;
-}
-
-
-std::string GetTHgProgRoot()
-{
- LPCSTR regname = "Software\\TortoiseHg";
+ LPCWSTR regname = L"Software\\TortoiseHg";
HKEY key = HKEY_LOCAL_MACHINE;
- TCHAR lpszValue[MAX_PATH] = "";
+ TCHAR lpszValue[MAX_PATH] = L"";
LONG lpcbLonger = MAX_PATH * sizeof(TCHAR);

if (RegQueryValue(key, regname, lpszValue, &lpcbLonger) != ERROR_SUCCESS)
- return "";
+ return L"";

return lpszValue;
}
@@ -51,32 +28,32 @@
// Note: if the command is a batch file and the [full] path to the
// batch contains spaces, the path must be double-quoted.
// (see http://www.encocoservices.com/createprocess.html)
-bool LaunchCommand(const std::string& command, const std::string& cwd)
+bool LaunchCommand(const std::wstring& command, const std::wstring& cwd)
{
- TDEBUG_TRACE("LaunchCommand: " << command);
- TDEBUG_TRACE("LaunchCommand: in " << cwd);
+ TDEBUG_TRACEW(L"LaunchCommand: " << command);
+ TDEBUG_TRACEW(L"LaunchCommand: in " << cwd);
PROCESS_INFORMATION processInfo;
memset(&processInfo, 0, sizeof(processInfo));

- STARTUPINFOA startupInfo;
+ STARTUPINFO startupInfo;
memset(&startupInfo, 0, sizeof(startupInfo));

- int res = CreateProcessA(
+ int res = CreateProcess(
NULL, // No module name, use command line
- const_cast<char*>(command.c_str()),
+ const_cast<wchar_t*>(command.c_str()),
NULL, // Process handle not inherited
NULL, // Thread handle not inherited
FALSE,
CREATE_NO_WINDOW,
NULL, // use parent's environment
- const_cast<char*>(cwd.c_str()),
+ const_cast<wchar_t*>(cwd.c_str()),
&startupInfo,
&processInfo
);

if (res == 0)
{
- TDEBUG_TRACE("LaunchCommand: failed to launch");
+ TDEBUG_TRACEW(L"LaunchCommand: failed to launch");
return false;
}

@@ -85,14 +62,14 @@
return true;
}

-std::string GetTemporaryFile(LPCTSTR prefix)
+std::wstring GetTemporaryFile(LPCWSTR prefix)
{
- char tempDir[MAX_PATH + 1];
- char tempFile[MAX_PATH + 1];
+ wchar_t tempDir[MAX_PATH + 1];
+ wchar_t tempFile[MAX_PATH + 1];

if (GetTempPath(MAX_PATH, tempDir) == 0)
{
- TDEBUG_TRACE("GetTemporaryFile: Failed to find temporary path");
+ TDEBUG_TRACEW(L"GetTemporaryFile: Failed to find temporary path");
}
else if (GetTempFileName(tempDir, prefix, 0, tempFile) != 0)
{
@@ -100,57 +77,57 @@
}
else
{
- TDEBUG_TRACE("GetTemporaryFile: Failed to get temporary file");
+ TDEBUG_TRACEW(L"GetTemporaryFile: Failed to get temporary file");
}

- return "";
+ return L"";
}


-bool IsDirectory(const std::string& filename)
+bool IsDirectory(const std::wstring& filename)
{
return ::PathIsDirectory(filename.c_str()) != 0;
}


-std::string DirName(const std::string& filename)
+std::wstring DirName(const std::wstring& filename)
{
if (filename.empty())
return filename;
- std::string::size_type pos = filename.find_last_of("\\");
- if (pos == std::string::npos)
- return "";
- std::string myfilename = filename.substr(0, pos);
- if (myfilename.size() > 0 && myfilename[myfilename.size()-1] == ':')
- myfilename.push_back('\\');
+ std::wstring::size_type pos = filename.find_last_of(L"\\");
+ if (pos == std::wstring::npos)
+ return L"";
+ std::wstring myfilename = filename.substr(0, pos);
+ if (myfilename.size() > 0 && myfilename[myfilename.size()-1] == L':')
+ myfilename.push_back(L'\\');
return myfilename;
}

-std::string BaseName(const std::string& filename)
+std::wstring BaseName(const std::wstring& filename)
{
if (filename.empty())
return filename;
- std::string::size_type pos = filename.find_last_of("\\");
- if (pos == std::string::npos)
+ std::wstring::size_type pos = filename.find_last_of(L"\\");
+ if (pos == std::wstring::npos)
return filename;
return filename.substr(pos+1);
}


// not reentrant
-HICON GetTortoiseIcon(const std::string& iconname)
+HICON GetTortoiseIcon(const std::wstring& iconname)
{
- typedef std::map<std::string, HICON> IconCacheT;
+ typedef std::map<std::wstring, HICON> IconCacheT;
static IconCacheT iconcache_;

- std::string thgdir = GetTHgProgRoot();
+ std::wstring thgdir = GetTHgProgRoot();
if (thgdir.empty())
{
- TDEBUG_TRACE("GetTortoiseIcon: THG root is empty");
+ TDEBUG_TRACEW(L"GetTortoiseIcon: THG root is empty");
return 0;
}

- const std::string iconpath = thgdir + "\\icons\\" + iconname;
+ const std::wstring iconpath = thgdir + L"\\icons\\" + iconname;

IconCacheT::const_iterator i = iconcache_.find(iconpath);
if (i != iconcache_.end())
@@ -158,48 +135,48 @@

if (iconcache_.size() > 200)
{
- TDEBUG_TRACE("**** GetTortoiseIcon: error: too many icons in cache");
+ TDEBUG_TRACEW(L"**** GetTortoiseIcon: error: too many icons in cache");
return 0;
}

- HICON h = (HICON) LoadImageA(0, iconpath.c_str(), IMAGE_ICON,
+ HICON h = (HICON) LoadImage(0, iconpath.c_str(), IMAGE_ICON,
16, 16, LR_LOADFROMFILE);
if (!h)
{
- TDEBUG_TRACE("GetTortoiseIcon: can't find " + iconpath);
+ TDEBUG_TRACEW(L"GetTortoiseIcon: can't find " + iconpath);
return 0;
}

iconcache_[iconpath] = h;

- TDEBUG_TRACE(
- "GetTortoiseIcon: added '" << iconpath << "' to iconcache_"
- " (" << iconcache_.size() << " icons in cache)"
+ TDEBUG_TRACEW(
+ L"GetTortoiseIcon: added '" << iconpath << L"' to iconcache_"
+ L" (" << iconcache_.size() << L" icons in cache)"
);

return h;
}


-std::string GetHgRepoRoot(const std::string& path)
+std::wstring GetHgRepoRoot(const std::wstring& path)
{
- TDEBUG_TRACE("GetHgRepoRoot('" << path << "')");
+ TDEBUG_TRACEW(L"GetHgRepoRoot('" << path << "')");

- std::string p =
+ std::wstring p =
(::PathIsUNCServerShare(path.c_str()) || IsDirectory(path))
? path : DirName(path);
for (;;)
{
- std::string tdir = p + "\\.hg";
+ std::wstring tdir = p + L"\\.hg";
if (::PathIsUNCServerShare(tdir.c_str()))
{
- TDEBUG_TRACE("GetHgRepoRoot: tdir is UNC share '" << tdir << "'");
+ TDEBUG_TRACEW(L"GetHgRepoRoot: tdir is UNC share '" << tdir << "'");
p.clear();
break;
}
else if (IsDirectory(tdir))
break;
- std::string oldp = p;
+ std::wstring oldp = p;
p = DirName(p);
if (p == oldp)
{
@@ -208,12 +185,12 @@
}
}

- TDEBUG_TRACE("GetHgRepoRoot: returning '" << p << "'");
+ TDEBUG_TRACEW(L"GetHgRepoRoot: returning '" << p << "'");
return p;
}


-bool IsHgRepo(const std::string& path)
+bool IsHgRepo(const std::wstring& path)
{
return !GetHgRepoRoot(path).empty();
}
@@ -221,9 +198,9 @@

// open a file for reading, allowing renames and deletes by other
// processes while we have it open
-FILE* fopenReadRenameAllowed(const char* path)
+FILE* fopenReadRenameAllowed(const wchar_t* path)
{
- HANDLE fh = ::CreateFileA(
+ HANDLE fh = ::CreateFile(
path, GENERIC_READ,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
0, OPEN_EXISTING, 0, 0
@@ -236,7 +213,7 @@
int fd = ::_open_osfhandle((intptr_t)fh, _O_RDONLY);
if (fd == -1)
{
- TDEBUG_TRACE("fopenReadRenameAllowed: _open_osfhandle failed");
+ TDEBUG_TRACEW(L"fopenReadRenameAllowed: _open_osfhandle failed");
::CloseHandle(fh);
return 0;
}
@@ -245,7 +222,7 @@
FILE* f = ::_fdopen(fd, "r");
if (f == 0)
{
- TDEBUG_TRACE("fopenReadRenameAllowed: _fdopen failed");
+ TDEBUG_TRACEW(L"fopenReadRenameAllowed: _fdopen failed");
::_close(fd);
return 0;
}
@@ -253,31 +230,6 @@
return f;
}

-
-// read string value from registry
-int GetRegSZValue(HKEY hkey, const char* name, std::string& res)
-{
- res = "";
-
- if (!hkey)
- return 0;
-
- std::vector<BYTE> Data(300);
- DWORD cbData = Data.size();
-
- LONG rv = ::RegQueryValueExA(hkey, name, 0, 0, &Data[0], &cbData);
-
- if (rv == ERROR_SUCCESS)
- {
- res = reinterpret_cast<char*>(&Data[0]);
- return 1;
- }
-
- TDEBUG_TRACE("GetRegSZValue(" << name << ") failed");
-
- return 0;
-}
-
// read string value from registry, wide version
int GetRegSZValueW(HKEY hkey, const wchar_t* name, std::wstring& res)
{
@@ -304,7 +256,7 @@


// true if a starts with b
-bool StartsWith(const std::string& a, const std::string& b)
+bool StartsWith(const std::wstring& a, const std::wstring& b)
{
if (a.empty() || b.empty())
return false;
@@ -312,7 +264,7 @@
if (b.size() > a.size())
return false;

- for (std::string::size_type i = 0; i < b.size(); ++i)
+ for (std::wstring::size_type i = 0; i < b.size(); ++i)
{
if (a[i] != b[i])
return false;
@@ -322,10 +274,10 @@
}


-void Tokenize(const std::string& str, std::vector<std::string>& tokens,
- const std::string& delimiters)
+void Tokenize(const std::wstring& str, std::vector<std::wstring>& tokens,
+ const std::wstring& delimiters)
{
- typedef std::string S;
+ typedef std::wstring S;
S::size_type lastpos = str.find_first_not_of(delimiters, 0);
S::size_type pos = str.find_first_of(delimiters, lastpos);

diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/TortoiseUtils.h
--- a/win32/shellext/TortoiseUtils.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/TortoiseUtils.h Wed Sep 01 23:02:36 2010 +0900
@@ -6,27 +6,20 @@
#include <string>
#include <vector>

-#define _MBSTR(wstr) hf_wctomb((LPSTR)alloca(wcslen(wstr) + 1), (wstr),wcslen(wstr) + 1)
-#define _WCSTR(str) hf_mbtowc((LPWSTR)alloca((strlen(str) + 1) * sizeof(WCHAR)),(str),strlen(str) + 1)
-
-LPWSTR hf_mbtowc(LPWSTR lpw, LPCSTR lpa, int nChars);
-LPSTR hf_wctomb(LPSTR lpa, LPCWSTR lpw, int nChars);
-
-std::string GetTHgProgRoot();
-std::string GetTemporaryFile(LPCSTR prefix="THG");
-bool IsDirectory(const std::string&);
-std::string DirName(const std::string&);
-std::string BaseName(const std::string&);
-bool LaunchCommand(const std::string& command, const std::string& cwd);
-HICON GetTortoiseIcon(const std::string & iconname);
-std::string GetHgRepoRoot(const std::string& path);
-bool IsHgRepo(const std::string& path);
-FILE* fopenReadRenameAllowed(const char* path);
-int GetRegSZValue(HKEY hkey, const char* name, std::string& res);
+std::wstring GetTHgProgRoot();
+std::wstring GetTemporaryFile(LPCWSTR prefix=L"THG");
+bool IsDirectory(const std::wstring&);
+std::wstring DirName(const std::wstring&);
+std::wstring BaseName(const std::wstring&);
+bool LaunchCommand(const std::wstring& command, const std::wstring& cwd);
+HICON GetTortoiseIcon(const std::wstring & iconname);
+std::wstring GetHgRepoRoot(const std::wstring& path);
+bool IsHgRepo(const std::wstring& path);
+FILE* fopenReadRenameAllowed(const wchar_t* path);
int GetRegSZValueW(HKEY hkey, const wchar_t* name, std::wstring& res);
-bool StartsWith(const std::string& a, const std::string& b);
-void Tokenize(const std::string& str, std::vector<std::string>& tokens,
- const std::string& delimiters = " ");
+bool StartsWith(const std::wstring& a, const std::wstring& b);
+void Tokenize(const std::wstring& str, std::vector<std::wstring>& tokens,
+ const std::wstring& delimiters = std::wstring(L" "));

template <typename C, typename T>
bool contains(const C& c, const T& t)
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/Winstat.cpp
--- a/win32/shellext/Winstat.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/Winstat.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -19,16 +19,16 @@
#include "Winstat.h"


-int Winstat::lstat(const char* file)
+int Winstat::lstat(const wchar_t* file)
{
const __int64 days_between_epochs = 134774L; /* days between 1.1.1601 and 1.1.1970 */
const __int64 secs_between_epochs = (__int64)days_between_epochs * 86400L;
const __int64 divisor = 10000000L;

- WIN32_FIND_DATAA data;
+ WIN32_FIND_DATA data;
HANDLE hfind;

- hfind = FindFirstFileA(file, &data);
+ hfind = FindFirstFile(file, &data);
if (hfind == INVALID_HANDLE_VALUE)
return -1;
FindClose(hfind);
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/Winstat.h
--- a/win32/shellext/Winstat.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/Winstat.h Wed Sep 01 23:02:36 2010 +0900
@@ -24,7 +24,7 @@
unsigned mtime;
bool isdir;

- int lstat(const char* file);
+ int lstat(const wchar_t* file);
};

#endif
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/Winstat64.cpp
--- a/win32/shellext/Winstat64.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/Winstat64.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -18,12 +18,12 @@

#include "Winstat64.h"

-int Winstat64::lstat(const char* path)
+int Winstat64::lstat(const wchar_t* path)
{
- WIN32_FIND_DATAA data;
+ WIN32_FIND_DATA data;
HANDLE hfind;

- hfind = FindFirstFileA(path, &data);
+ hfind = FindFirstFile(path, &data);
if (hfind == INVALID_HANDLE_VALUE)
return -1;
FindClose(hfind);
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/Winstat64.h
--- a/win32/shellext/Winstat64.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/Winstat64.h Wed Sep 01 23:02:36 2010 +0900
@@ -21,7 +21,7 @@
{
__int64 mtime;
__int64 size;
- int lstat(const char* path);
+ int lstat(const wchar_t* path);
};

#endif
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/dirstate.cpp
--- a/win32/shellext/dirstate.cpp Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/dirstate.cpp Wed Sep 01 23:02:36 2010 +0900
@@ -19,16 +19,16 @@

#include "dirstate.h"
#include "TortoiseUtils.h"
+#include "StringUtils.h"

-
-std::auto_ptr<Dirstate> Dirstate::read(const std::string& path, bool& unset)
+std::auto_ptr<Dirstate> Dirstate::read(const std::wstring& path, bool& unset)
{
unset = false;

FILE *f = fopenReadRenameAllowed(path.c_str());
if (!f)
{
- TDEBUG_TRACE("Dirstate::read: can't open " << path);
+ TDEBUG_TRACEW(L"Dirstate::read: can't open " << path);
return std::auto_ptr<Dirstate>(0);
}

@@ -38,20 +38,24 @@
fread(&pd->parent2, sizeof(char), HASH_LENGTH, f);

Direntry e;
- std::vector<char> relpath(MAX_PATH + 10, 0);
+ std::vector<char> relpath(MAX_PATH + 10, 0); // UTF-8 if fixutf8 enabled
while (e.read(f, relpath))
{
if (e.unset())
+ {
unset = true;
+ }
+ if (e.state == 'a')
+ {
+ ++pd->num_added_;
+ }

- if (e.state == 'a')
- ++pd->num_added_;
-
- pd->add(&relpath[0], e);
+ std::wstring urelpath = ThgMultibyteToWide ( &relpath[0] ) ;
+ ::CharLowerBuff(&urelpath[0], urelpath.length());
+ pd->add(urelpath, e);
}

fclose(f);
-
return pd;
}

@@ -74,13 +78,13 @@
void testread()
{
bool unset;
- std::auto_ptr<Dirstate> pd = Dirstate::read(".hg/dirstate", unset);
+ std::auto_ptr<Dirstate> pd = Dirstate::read(L".hg/dirstate", unset);
if (!pd.get()) {
printf("error: could not read .hg/dirstate\n");
return;
}
time_t t;
- char *s;
+ wchar_t *s;
unsigned ix;
printf("parent1: %s\n", revhash_string(pd->parent1));
printf("parent2: %s\n", revhash_string(pd->parent2));
@@ -91,7 +95,7 @@


#ifdef APPMAIN
-int main(int argc, char *argv[])
+int main(int argc, wchar_t *argv[])
{
testread();
return 0;
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/dirstate.h
--- a/win32/shellext/dirstate.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/dirstate.h Wed Sep 01 23:02:36 2010 +0900
@@ -36,11 +36,11 @@
char parent1[HASH_LENGTH];
char parent2[HASH_LENGTH];

- static std::auto_ptr<Dirstate> read(const std::string& path, bool& unset);
+ static std::auto_ptr<Dirstate> read(const std::wstring& path, bool& unset);

Directory& root() { return root_; }

- void add(const std::string& relpath, Direntry& e) {
+ void add(const std::wstring& relpath, Direntry& e) {
root_.add(relpath, e);
++num_entries_;
}
@@ -50,7 +50,7 @@

private:
Dirstate()
- : root_(0, "", ""), num_added_(0), num_entries_(0) {}
+ : root_(0, L"", L""), num_added_(0), num_entries_(0) {}
};

#endif
diff -r 30b5e85be646 -r aaea8a88dec9 win32/shellext/stdafx.h
--- a/win32/shellext/stdafx.h Wed Sep 01 00:27:42 2010 -0500
+++ b/win32/shellext/stdafx.h Wed Sep 01 23:02:36 2010 +0900
@@ -31,15 +31,6 @@
#define THG_PREFIXL L"[THGx86] "
#endif

- // TDEBUG_TRACE() prints debugging messages to Windows' debugger display.
- // The messages can be viewed with Sysinternals DebugView, which may be
- // downloaded from Microsoft TechNet.
- #define TDEBUG_TRACE(s) if (ThgDebug::enabled()) { \
- std::stringstream _the_msg; \
- _the_msg << THG_PREFIX << s; \
- std::string _the_str = _the_msg.str(); \
- OutputDebugStringA(_the_str.c_str()); \
- }
#define TDEBUG_TRACEW(s) if (ThgDebug::enabled()) { \
std::basic_stringstream<wchar_t> _the_msg; \
_the_msg << THG_PREFIXL << s; \

Steve Borho

unread,
Sep 1, 2010, 11:32:49 AM9/1/10
to thg...@googlegroups.com
On Wed, Sep 1, 2010 at 9:20 AM, Toshi MARUYAMA <marut...@gmail.com> wrote:
> # HG changeset patch
> # User Toshi MARUYAMA <marut...@gmail.com>
> # Date 1283350110 -32400
> # Node ID c56bb020d0d5f33c0fdfd7326aaca6e49ced88c3
> # Parent  aaea8a88dec973ad0b6e814bae16d7805e84b615
> OverlayServer: catch exception of os.listdir(path).
>
> This exception raises in case of
> fixutf8 extension enabled and folder name contains '0x5c'(backslash).

I pushed a cleaned up version of this patch

> diff -r aaea8a88dec9 -r c56bb020d0d5 TortoiseHgOverlayServer.py
> --- a/TortoiseHgOverlayServer.py        Wed Sep 01 23:02:36 2010 +0900
> +++ b/TortoiseHgOverlayServer.py        Wed Sep 01 23:08:30 2010 +0900
> @@ -203,11 +203,17 @@
>     for path in batch:
>         r = paths.find_root(path)
>         if r is None:
> +          try:
>             for n in os.listdir(path):
>                 r = paths.find_root(os.path.join(path, n))
>                 if (r is not None):
>                     roots.add(r)
>                     notifypaths.add(r)
> +          except Exception, e:
> +            # This exception raises in case of
> +            # fixutf8 extension enabled and folder name contains '0x5c'(backslash).
> +            logger.msg('Failed listdir %s (%s)' % (path, str(e)))
> +            pass
>         else:
>             roots.add(r);
>             notifypaths.add(path)
>

--
Steve Borho

Steve Borho

unread,
Sep 1, 2010, 11:57:10 AM9/1/10
to thg...@googlegroups.com
On Wed, Sep 1, 2010 at 9:20 AM, Toshi MARUYAMA <marut...@gmail.com> wrote:
> # HG changeset patch
> # User Toshi MARUYAMA <marut...@gmail.com>
> # Date 1283349756 -32400
> # Node ID aaea8a88dec973ad0b6e814bae16d7805e84b615
> # Parent  30b5e85be646d321a8b9e5f8d661e487dce7f69e
> win32shellext: Unicode porting and context-menu disabled on special folders (e.g. start-menu)
>
> Issue #1241.
>
> Merge squashed following jobs.
>
> * Marco Lizza's patches exclude tortoisehg_rev6547.patch (Msi.lib).
>  http://groups.google.com/group/thg-dev/browse_thread/thread/8580c791fe5b52b2
>
> * Tinyfish's Unicode porting.
>  http://bitbucket.org/tinyfish/tortoisehg.winutf8/changeset/cdce65b00f1e

I'm leary of pushing this to the main repo for a number of reasons.
The changes between 1.1 and 2.0 are already enormous and I'd like to
keep at least the shell extension essentially stable while the Qt port
matures. I think the cmenu changes I made this week are the last
changes we require for the 2.0 release.

However, I would like to make your patched extensions more visible so
users that need them are aware of them. Perhaps this means including
them as an option in the final installers, but in the least our
official documentation needs to mention their existence, the problems
they solve, and the steps necessary to download and use them.

--
Steve Borho

Toshi MARUYAMA

unread,
Sep 1, 2010, 5:45:58 PM9/1/10
to TortoiseHg Developers

On Sep 2, 0:57, Steve Borho <st...@borho.org> wrote:
> On Wed, Sep 1, 2010 at 9:20 AM, Toshi MARUYAMA <marutosi...@gmail.com> wrote:
> > # HG changeset patch
> > # User Toshi MARUYAMA <marutosi...@gmail.com>
> > # Date 1283349756 -32400
> > # Node ID aaea8a88dec973ad0b6e814bae16d7805e84b615
> > # Parent  30b5e85be646d321a8b9e5f8d661e487dce7f69e
> > win32shellext: Unicode porting and context-menu disabled on special folders (e.g. start-menu)
>
> > Issue #1241.
>
> > Merge squashed following jobs.
>
> > * Marco Lizza's patches exclude tortoisehg_rev6547.patch (Msi.lib).
> >  http://groups.google.com/group/thg-dev/browse_thread/thread/8580c791f...
>
> > * Tinyfish's Unicode porting.
> >  http://bitbucket.org/tinyfish/tortoisehg.winutf8/changeset/cdce65b00f1e
>
> I'm leary of pushing this to the main repo for a number of reasons.

Sorry, I can't understand the meaning of 'leary'.
http://www.ldoceonline.com/spellcheck/?q=leary

Steve Borho

unread,
Sep 1, 2010, 9:07:55 PM9/1/10
to thg...@googlegroups.com
On Wed, Sep 1, 2010 at 4:45 PM, Toshi MARUYAMA <marut...@gmail.com> wrote:
>
> On Sep 2, 0:57, Steve Borho <st...@borho.org> wrote:
>> On Wed, Sep 1, 2010 at 9:20 AM, Toshi MARUYAMA <marutosi...@gmail.com> wrote:
>> > # HG changeset patch
>> > # User Toshi MARUYAMA <marutosi...@gmail.com>
>> > # Date 1283349756 -32400
>> > # Node ID aaea8a88dec973ad0b6e814bae16d7805e84b615
>> > # Parent  30b5e85be646d321a8b9e5f8d661e487dce7f69e
>> > win32shellext: Unicode porting and context-menu disabled on special folders (e.g. start-menu)
>>
>> > Issue #1241.
>>
>> > Merge squashed following jobs.
>>
>> > * Marco Lizza's patches exclude tortoisehg_rev6547.patch (Msi.lib).
>> >  http://groups.google.com/group/thg-dev/browse_thread/thread/8580c791f...
>>
>> > * Tinyfish's Unicode porting.
>> >  http://bitbucket.org/tinyfish/tortoisehg.winutf8/changeset/cdce65b00f1e
>>
>> I'm leary of pushing this to the main repo for a number of reasons.
>
> Sorry, I can't understand the meaning of 'leary'.
> http://www.ldoceonline.com/spellcheck/?q=leary

That's because I misspelled 'leery'. The dictionary definition of
leery is a bit harsh. Perhaps 'hesitant' would have been a better
word. I would like to limit the amount of risk we take in this
component for now, since nearly every other component is being
re-written from scratch.

--
Steve Borho

Toshi MARUYAMA

unread,
Sep 1, 2010, 9:16:45 PM9/1/10
to TortoiseHg Developers

On Nov 2 , 10:07, Steve Borho <st...@borho.org> wrote:
Do you mean all C++ will be re-written from scratch?

Steve Borho

unread,
Sep 1, 2010, 9:45:11 PM9/1/10
to thg...@googlegroups.com

No, I mean that nearly all of the Python code is currently being
re-written, so I prefer not to take large changes to the C++ code at
the same time.

--
Steve Borho

Toshi MARUYAMA

unread,
Sep 1, 2010, 10:04:09 PM9/1/10
to TortoiseHg Developers

On 9月2日, 10:45 AM, Steve Borho <st...@borho.org> wrote:
I see.
There is a wiki "New C++ Shell Extension Plan".
http://bitbucket.org/tortoisehg/stable/wiki/developers/NewShellExtensionPlan
Should I add a description on this wiki, or add new wiki page on thg,
or create new wiki on my repository?



Steve Borho

unread,
Sep 1, 2010, 10:11:22 PM9/1/10
to thg...@googlegroups.com

This page should probably be removed, or at least unlinked. The
effort was never started.

> Should I add a description on this wiki, or add new wiki page on thg,
> or create new wiki on my repository?

The best approach would be for you to create a wiki on your
repository, then link to it from the official front wiki page.

--
Steve Borho

Reply all
Reply to author
Forward
0 new messages