mirror of
https://github.com/HackPlan/winsparkle.git
synced 2026-04-29 18:45:06 +08:00
Fix downloading updates if the user directory is non-ASCII.
Use Unicode APIs everywhere related to filenames, including the temporary directory. Fixes #26.
This commit is contained in:
@@ -102,10 +102,11 @@ bool GetHttpHeader(HINTERNET handle, DWORD whatToGet, DWORD& output)
|
|||||||
) == TRUE;
|
) == TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetURLFileName(const URL_COMPONENTSA& urlc)
|
std::wstring GetURLFileName(const URL_COMPONENTSA& urlc)
|
||||||
{
|
{
|
||||||
const char *lastSlash = strrchr(urlc.lpszUrlPath, '/');
|
const char *lastSlash = strrchr(urlc.lpszUrlPath, '/');
|
||||||
return std::string(lastSlash ? lastSlash + 1 : urlc.lpszUrlPath);
|
const std::string fn(lastSlash ? lastSlash + 1 : urlc.lpszUrlPath);
|
||||||
|
return AnsiToWide(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
@@ -201,8 +202,7 @@ void DownloadFile(const std::string& url, IDownloadSink *sink, int flags)
|
|||||||
else
|
else
|
||||||
*ptr2 = 0;
|
*ptr2 = 0;
|
||||||
|
|
||||||
std::string filename( c_filename );
|
sink->SetFilename(AnsiToWide(c_filename));
|
||||||
sink->SetFilename(filename);
|
|
||||||
filename_set = true;
|
filename_set = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ struct IDownloadSink
|
|||||||
/**
|
/**
|
||||||
Inform the sink of detected filename
|
Inform the sink of detected filename
|
||||||
*/
|
*/
|
||||||
virtual void SetFilename(const std::string& filename) = 0;
|
virtual void SetFilename(const std::wstring& filename) = 0;
|
||||||
|
|
||||||
/// Add chunk of downloaded data
|
/// Add chunk of downloaded data
|
||||||
virtual void Add(const void *data, size_t len) = 0;
|
virtual void Add(const void *data, size_t len) = 0;
|
||||||
@@ -59,7 +59,7 @@ struct StringDownloadSink : public IDownloadSink
|
|||||||
{
|
{
|
||||||
virtual void SetLength(size_t) {}
|
virtual void SetLength(size_t) {}
|
||||||
|
|
||||||
virtual void SetFilename(const std::string& filename) {}
|
virtual void SetFilename(const std::wstring&) {}
|
||||||
|
|
||||||
virtual void Add(const void *data, size_t len)
|
virtual void Add(const void *data, size_t len)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ std::string Settings::GetDefaultRegistryPath()
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
void RegistryWrite(const char *name, const char *value)
|
void RegistryWrite(const char *name, const wchar_t *value)
|
||||||
{
|
{
|
||||||
const std::string subkey = Settings::GetRegistryPath();
|
const std::string subkey = Settings::GetRegistryPath();
|
||||||
|
|
||||||
@@ -198,14 +198,14 @@ void RegistryWrite(const char *name, const char *value)
|
|||||||
if ( result != ERROR_SUCCESS )
|
if ( result != ERROR_SUCCESS )
|
||||||
throw Win32Exception("Cannot write settings to registry");
|
throw Win32Exception("Cannot write settings to registry");
|
||||||
|
|
||||||
result = RegSetValueExA
|
result = RegSetValueEx
|
||||||
(
|
(
|
||||||
key,
|
key,
|
||||||
name,
|
AnsiToWide(name).c_str(),
|
||||||
0,
|
0,
|
||||||
REG_SZ,
|
REG_SZ,
|
||||||
(const BYTE*)value,
|
(const BYTE*)value,
|
||||||
strlen(value) + 1
|
(wcslen(value) + 1) * sizeof(wchar_t)
|
||||||
);
|
);
|
||||||
|
|
||||||
RegCloseKey(key);
|
RegCloseKey(key);
|
||||||
@@ -240,7 +240,7 @@ void RegistryDelete(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int DoRegistryRead(HKEY root, const char *name, char *buf, size_t len)
|
int DoRegistryRead(HKEY root, const char *name, wchar_t *buf, size_t len)
|
||||||
{
|
{
|
||||||
const std::string subkey = Settings::GetRegistryPath();
|
const std::string subkey = Settings::GetRegistryPath();
|
||||||
|
|
||||||
@@ -262,10 +262,10 @@ int DoRegistryRead(HKEY root, const char *name, char *buf, size_t len)
|
|||||||
|
|
||||||
DWORD buflen = len;
|
DWORD buflen = len;
|
||||||
DWORD type;
|
DWORD type;
|
||||||
result = RegQueryValueExA
|
result = RegQueryValueEx
|
||||||
(
|
(
|
||||||
key,
|
key,
|
||||||
name,
|
AnsiToWide(name).c_str(),
|
||||||
0,
|
0,
|
||||||
&type,
|
&type,
|
||||||
(BYTE*)buf,
|
(BYTE*)buf,
|
||||||
@@ -292,7 +292,7 @@ int DoRegistryRead(HKEY root, const char *name, char *buf, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int RegistryRead(const char *name, char *buf, size_t len)
|
int RegistryRead(const char *name, wchar_t *buf, size_t len)
|
||||||
{
|
{
|
||||||
// Try reading from HKCU first. If that fails, look at HKLM too, in case
|
// Try reading from HKCU first. If that fails, look at HKLM too, in case
|
||||||
// some settings have globally set values (either by the installer or the
|
// some settings have globally set values (either by the installer or the
|
||||||
@@ -313,7 +313,7 @@ CriticalSection g_csConfigValues;
|
|||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
void Settings::DoWriteConfigValue(const char *name, const char *value)
|
void Settings::DoWriteConfigValue(const char *name, const wchar_t *value)
|
||||||
{
|
{
|
||||||
CriticalSectionLocker lock(g_csConfigValues);
|
CriticalSectionLocker lock(g_csConfigValues);
|
||||||
|
|
||||||
@@ -321,15 +321,15 @@ void Settings::DoWriteConfigValue(const char *name, const char *value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string Settings::DoReadConfigValue(const char *name)
|
std::wstring Settings::DoReadConfigValue(const char *name)
|
||||||
{
|
{
|
||||||
CriticalSectionLocker lock(g_csConfigValues);
|
CriticalSectionLocker lock(g_csConfigValues);
|
||||||
|
|
||||||
char buf[512];
|
wchar_t buf[512];
|
||||||
if ( RegistryRead(name, buf, sizeof(buf)) )
|
if ( RegistryRead(name, buf, sizeof(buf)) )
|
||||||
return buf;
|
return buf;
|
||||||
else
|
else
|
||||||
return std::string();
|
return std::wstring();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::DeleteConfigValue(const char *name)
|
void Settings::DeleteConfigValue(const char *name)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#define _settings_h_
|
#define _settings_h_
|
||||||
|
|
||||||
#include "threads.h"
|
#include "threads.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -176,24 +177,49 @@ public:
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
static void WriteConfigValue(const char *name, const T& value)
|
static void WriteConfigValue(const char *name, const T& value)
|
||||||
{
|
{
|
||||||
std::ostringstream s;
|
std::wostringstream s;
|
||||||
s << value;
|
s << value;
|
||||||
DoWriteConfigValue(name, s.str().c_str());
|
DoWriteConfigValue(name, s.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void WriteConfigValue(const char *name, const std::string& value)
|
||||||
|
{
|
||||||
|
DoWriteConfigValue(name, AnsiToWide(value).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteConfigValue(const char *name, const std::wstring& value)
|
||||||
|
{
|
||||||
|
DoWriteConfigValue(name, value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
// Reads a value from registry. Returns true if it was present,
|
// Reads a value from registry. Returns true if it was present,
|
||||||
// false otherwise.
|
// false otherwise.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static bool ReadConfigValue(const char *name, T& value)
|
static bool ReadConfigValue(const char *name, T& value)
|
||||||
{
|
{
|
||||||
const std::string v = DoReadConfigValue(name);
|
const std::wstring v = DoReadConfigValue(name);
|
||||||
if ( v.empty() )
|
if ( v.empty() )
|
||||||
return false;
|
return false;
|
||||||
std::istringstream s(v);
|
std::wistringstream s(v);
|
||||||
s >> value;
|
s >> value;
|
||||||
return !s.fail();
|
return !s.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ReadConfigValue(const char *name, std::string& value)
|
||||||
|
{
|
||||||
|
const std::wstring v = DoReadConfigValue(name);
|
||||||
|
if (v.empty())
|
||||||
|
return false;
|
||||||
|
value = WideToAnsi(v);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ReadConfigValue(const char *name, std::wstring& value)
|
||||||
|
{
|
||||||
|
value = DoReadConfigValue(name);
|
||||||
|
return !value.empty();
|
||||||
|
}
|
||||||
|
|
||||||
// Reads a value from registry, substituting default value if not present.
|
// Reads a value from registry, substituting default value if not present.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static bool ReadConfigValue(const char *name, T& value, const T& defval)
|
static bool ReadConfigValue(const char *name, T& value, const T& defval)
|
||||||
@@ -225,8 +251,8 @@ private:
|
|||||||
|
|
||||||
static std::string GetDefaultRegistryPath();
|
static std::string GetDefaultRegistryPath();
|
||||||
|
|
||||||
static void DoWriteConfigValue(const char *name, const char *value);
|
static void DoWriteConfigValue(const char *name, const wchar_t *value);
|
||||||
static std::string DoReadConfigValue(const char *name);
|
static std::wstring DoReadConfigValue(const char *name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// guards the variables below:
|
// guards the variables below:
|
||||||
|
|||||||
12
src/ui.cpp
12
src/ui.cpp
@@ -143,9 +143,9 @@ wxIcon GetApplicationIcon()
|
|||||||
|
|
||||||
struct EventPayload
|
struct EventPayload
|
||||||
{
|
{
|
||||||
Appcast appcast;
|
Appcast appcast;
|
||||||
size_t sizeDownloaded, sizeTotal;
|
size_t sizeDownloaded, sizeTotal;
|
||||||
std::string updateFile;
|
std::wstring updateFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -283,7 +283,7 @@ public:
|
|||||||
// update download progress
|
// update download progress
|
||||||
void DownloadProgress(size_t downloaded, size_t total);
|
void DownloadProgress(size_t downloaded, size_t total);
|
||||||
// change state into "update downloaded"
|
// change state into "update downloaded"
|
||||||
void StateUpdateDownloaded(const std::string& updateFile);
|
void StateUpdateDownloaded(const std::wstring& updateFile);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void EnablePulsing(bool enable);
|
void EnablePulsing(bool enable);
|
||||||
@@ -713,7 +713,7 @@ void UpdateDialog::DownloadProgress(size_t downloaded, size_t total)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UpdateDialog::StateUpdateDownloaded(const std::string& updateFile)
|
void UpdateDialog::StateUpdateDownloaded(const std::wstring& updateFile)
|
||||||
{
|
{
|
||||||
m_downloader->Join();
|
m_downloader->Join();
|
||||||
delete m_downloader;
|
delete m_downloader;
|
||||||
@@ -1221,7 +1221,7 @@ void UI::NotifyDownloadProgress(size_t downloaded, size_t total)
|
|||||||
|
|
||||||
|
|
||||||
/*static*/
|
/*static*/
|
||||||
void UI::NotifyUpdateDownloaded(const std::string& updateFile)
|
void UI::NotifyUpdateDownloaded(const std::wstring& updateFile)
|
||||||
{
|
{
|
||||||
UIThreadAccess uit;
|
UIThreadAccess uit;
|
||||||
EventPayload payload;
|
EventPayload payload;
|
||||||
|
|||||||
2
src/ui.h
2
src/ui.h
@@ -86,7 +86,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
Notifies the UI that an update was downloaded.
|
Notifies the UI that an update was downloaded.
|
||||||
*/
|
*/
|
||||||
static void NotifyUpdateDownloaded(const std::string& updateFile);
|
static void NotifyUpdateDownloaded(const std::wstring& updateFile);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Shows the WinSparkle window in "checking for updates..." state.
|
Shows the WinSparkle window in "checking for updates..." state.
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace winsparkle
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
std::string CreateUniqueTempDirectory()
|
std::wstring CreateUniqueTempDirectory()
|
||||||
{
|
{
|
||||||
// We need to put downloaded updates into a directory of their own, because
|
// We need to put downloaded updates into a directory of their own, because
|
||||||
// if we put it in $TMP, some DLLs could be there and interfere with the
|
// if we put it in $TMP, some DLLs could be there and interfere with the
|
||||||
@@ -53,25 +53,23 @@ std::string CreateUniqueTempDirectory()
|
|||||||
//
|
//
|
||||||
// This code creates a new randomized directory name and tries to create it;
|
// This code creates a new randomized directory name and tries to create it;
|
||||||
// this process is repeated if the directory already exists.
|
// this process is repeated if the directory already exists.
|
||||||
char tmpdir[MAX_PATH+1];
|
wchar_t tmpdir[MAX_PATH+1];
|
||||||
if ( GetTempPathA(sizeof(tmpdir), tmpdir) == 0 )
|
if ( GetTempPath(MAX_PATH+1, tmpdir) == 0 )
|
||||||
throw Win32Exception("Cannot create temporary directory");
|
throw Win32Exception("Cannot create temporary directory");
|
||||||
|
|
||||||
for ( ;; )
|
for ( ;; )
|
||||||
{
|
{
|
||||||
std::ostringstream sdir;
|
std::wstring dir(tmpdir);
|
||||||
sdir << tmpdir << "Update-";
|
dir += L"Update-";
|
||||||
|
|
||||||
UUID uuid;
|
UUID uuid;
|
||||||
UuidCreate(&uuid);
|
UuidCreate(&uuid);
|
||||||
RPC_CSTR uuidStr;
|
RPC_WSTR uuidStr;
|
||||||
UuidToStringA(&uuid, &uuidStr);
|
RPC_STATUS status = UuidToString(&uuid, &uuidStr);
|
||||||
sdir << uuidStr;
|
dir += reinterpret_cast<wchar_t*>(uuidStr);
|
||||||
RpcStringFreeA(&uuidStr);
|
RpcStringFree(&uuidStr);
|
||||||
|
|
||||||
const std::string dir(sdir.str());
|
if ( CreateDirectory(dir.c_str(), NULL) )
|
||||||
|
|
||||||
if ( CreateDirectoryA(dir.c_str(), NULL) )
|
|
||||||
return dir;
|
return dir;
|
||||||
else if ( GetLastError() != ERROR_ALREADY_EXISTS )
|
else if ( GetLastError() != ERROR_ALREADY_EXISTS )
|
||||||
throw Win32Exception("Cannot create temporary directory");
|
throw Win32Exception("Cannot create temporary directory");
|
||||||
@@ -80,9 +78,9 @@ std::string CreateUniqueTempDirectory()
|
|||||||
|
|
||||||
struct UpdateDownloadSink : public IDownloadSink
|
struct UpdateDownloadSink : public IDownloadSink
|
||||||
{
|
{
|
||||||
UpdateDownloadSink(Thread& thread, const std::string& dir)
|
UpdateDownloadSink(Thread& thread, const std::wstring& dir)
|
||||||
: m_thread(thread),
|
: m_thread(thread),
|
||||||
m_dir(dir), m_path(""), m_file(NULL),
|
m_dir(dir), m_file(NULL),
|
||||||
m_downloaded(0), m_total(0), m_lastUpdate(-1)
|
m_downloaded(0), m_total(0), m_lastUpdate(-1)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -97,17 +95,17 @@ struct UpdateDownloadSink : public IDownloadSink
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetFilePath(void) { return m_path; }
|
std::wstring GetFilePath(void) { return m_path; }
|
||||||
|
|
||||||
virtual void SetLength(size_t l) { m_total = l; }
|
virtual void SetLength(size_t l) { m_total = l; }
|
||||||
|
|
||||||
virtual void SetFilename(const std::string& filename)
|
virtual void SetFilename(const std::wstring& filename)
|
||||||
{
|
{
|
||||||
if ( m_file )
|
if ( m_file )
|
||||||
throw std::runtime_error("Update file already set");
|
throw std::runtime_error("Update file already set");
|
||||||
|
|
||||||
m_path = m_dir + "\\" + filename;
|
m_path = m_dir + L"\\" + filename;
|
||||||
m_file = fopen(m_path.c_str(), "wb");
|
m_file = _wfopen(m_path.c_str(), L"wb");
|
||||||
if ( !m_file )
|
if ( !m_file )
|
||||||
throw std::runtime_error("Cannot save update file");
|
throw std::runtime_error("Cannot save update file");
|
||||||
}
|
}
|
||||||
@@ -136,8 +134,8 @@ struct UpdateDownloadSink : public IDownloadSink
|
|||||||
Thread& m_thread;
|
Thread& m_thread;
|
||||||
size_t m_downloaded, m_total;
|
size_t m_downloaded, m_total;
|
||||||
FILE *m_file;
|
FILE *m_file;
|
||||||
std::string m_dir;
|
std::wstring m_dir;
|
||||||
std::string m_path;
|
std::wstring m_path;
|
||||||
clock_t m_lastUpdate;
|
clock_t m_lastUpdate;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -166,7 +164,7 @@ void UpdateDownloader::Run()
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const std::string tmpdir = CreateUniqueTempDirectory();
|
const std::wstring tmpdir = CreateUniqueTempDirectory();
|
||||||
Settings::WriteConfigValue("UpdateTempDir", tmpdir);
|
Settings::WriteConfigValue("UpdateTempDir", tmpdir);
|
||||||
|
|
||||||
UpdateDownloadSink sink(*this, tmpdir);
|
UpdateDownloadSink sink(*this, tmpdir);
|
||||||
|
|||||||
Reference in New Issue
Block a user