Fix failure to start application after install on Windows systems which do not have the required side-by-side libraries installed system-wide.

It appears that the previous fix was incorrect.  The issue was
not with the current directory used by the process but that
the executable path passed to CreateProcess() used forward
slashes instead of back slashes.  A runtime error in loading
the WinSxS DLLs (the C++ runtime library) resulted.

Although most Windows API functions both back and forward slashes,
this appears not to be the case for loading of side-by-side
DLLs from the application's directory under Windows XP.

This may be related to the LoadLibrary() function whose documentation
specifies that backslashes must be used instead of forward slashes.

This commit converts the executable path to use backslashes before passing
it to CreateProcess() and removes the previous change to alter the
current working directory before starting the main app binary.
This commit is contained in:
Robert Knight 2011-09-27 15:30:06 +01:00
parent 61e8c92550
commit 3319c4ad3e
4 changed files with 27 additions and 20 deletions

View file

@ -5,6 +5,7 @@
#include "Platform.h"
#include "StringUtils.h"
#include <algorithm>
#include <assert.h>
#include <string.h>
#include <fstream>
@ -320,10 +321,12 @@ std::string FileUtils::dirname(const char* path)
free(pathCopy);
return dirname;
#else
char drive[3];
char dir[MAX_PATH];
_splitpath_s(path,
0, /* drive */
0, /* drive length */
drive, /* drive */
3, /* drive length */
dir,
MAX_PATH, /* dir length */
0, /* filename */
@ -331,6 +334,7 @@ std::string FileUtils::dirname(const char* path)
0, /* extension */
0 /* extension length */
);
return std::string(dir);
#endif
}
@ -422,16 +426,17 @@ std::string FileUtils::canonicalPath(const char* path)
#endif
}
std::string FileUtils::toWindowsPathSeparators(const std::string& str)
{
std::string result = str;
std::replace(result.begin(),result.end(),'/','\\');
return result;
}
std::string FileUtils::toUnixPathSeparators(const std::string& str)
{
std::string result = str;
for (size_t i=0; i < result.size(); i++)
{
if (result[i] == '\\')
{
result[i] = '/';
}
}
std::replace(result.begin(),result.end(),'\\','/');
return result;
}

View file

@ -108,6 +108,8 @@ class FileUtils
*/
static std::string toUnixPathSeparators(const std::string& str);
static std::string toWindowsPathSeparators(const std::string& str);
/** Returns true if the provided path is relative.
* Or false if absolute.
*/

View file

@ -402,10 +402,20 @@ PLATFORM_PID ProcessUtils::runAsyncUnix(const std::string& executable,
#endif
#ifdef PLATFORM_WINDOWS
int ProcessUtils::runWindows(const std::string& executable,
int ProcessUtils::runWindows(const std::string& _executable,
const std::list<std::string>& _args,
RunMode runMode)
{
// most Windows API functions allow back and forward slashes to be
// used interchangeably. However, an application started with
// CreateProcess() may fail to find Side-by-Side library dependencies
// in the same directory as the executable if forward slashes are
// used as path separators, so convert the path to use back slashes here.
//
// This may be related to LoadLibrary() requiring backslashes instead
// of forward slashes.
std::string executable = FileUtils::toWindowsPathSeparators(_executable);
std::list<std::string> args(_args);
args.push_front(executable);
std::string commandLine = quoteArgs(args);

View file

@ -420,17 +420,7 @@ void UpdateInstaller::restartMainApp()
if (!command.empty())
{
LOG(Info,"Starting main application " + command);
// change the current directory to that of the application binary,
// so that on Windows the application can find shared libraries
// that it depends on which are in the same directory
std::string appDir = FileUtils::dirname(command.c_str());
std::string currentDir = FileUtils::getcwd();
FileUtils::chdir(appDir.c_str());
ProcessUtils::runAsync(command,args);
FileUtils::chdir(currentDir.c_str());
}
else
{