Jean-Marc,
the attached patch enables LyX 1.3.x to at least fire up under Win98.
Whether the resulting executable is any use is a separate issue, as
mentioned here: http://wiki.lyx.org/Windows/LyX136experimental#win98
The patch does three things:
1. Ensures that various char arrays have max size of PATH_MAX. Early
versions of Windows require it for some system functions.
2. Pass file names input from "outside" through GetLongPathName. This fixes
the problem with 8.3 file names reported by Sven Schreiber. (See Squashed
LyX Bugs on the same web page.)
3. Loads up shfolder.dll dynamically. It transpires that whilst
SHGetFolderPathA can be accessed from shell32.dll on Win2K and newer
machines, Microsoft recommend that the portable way to access the function
is through shfolder.dll.
http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/shgetfolderpath.asp
I'm unsure which route we should go down on this one; do we need this
dynamic link stuff or should we ensure that we link against shfolder.dll
at link time?
--
Angus
Index: src/support/package.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/Attic/package.C,v
retrieving revision 1.1.2.6
diff -u -p -r1.1.2.6 package.C
--- src/support/package.C 15 Jul 2005 15:57:10 -0000 1.1.2.6
+++ src/support/package.C 8 Sep 2005 22:04:59 -0000
@@ -22,6 +22,7 @@
#include "support/lstrings.h"
#include "support/os.h"
+#include <boost/scoped_ptr.hpp>
#include <boost/tuple/tuple.hpp>
#include <list>
@@ -121,6 +122,32 @@ std::pair<string, bool> const
get_user_support_dir(string const & default_user_support_dir,
string const & command_line_user_support_dir);
+#if defined (USE_WINDOWS_PACKAGING)
+
+/** Win98 and earlier don't have SHGetFolderPath in shell32.dll.
+ * Microsoft recommend that we load shfolder.dll at run time and
+ * access the function through that. It will work on all versions
+ * of Windows from Win95.
+ *
+ * This class wraps the LoadLibrary and FreeLibrary calls and
+ * makes SHGetFolderPath through its function operator.
+ */
+class GetFolderPath {
+public:
+ typedef HRESULT (__stdcall * FuncPtr)(HWND, int, HANDLE, DWORD, LPCSTR);
+
+ GetFolderPath();
+ ~GetFolderPath();
+ HRESULT operator()(HWND, int, HANDLE, DWORD, LPCSTR) const;
+private:
+ HMODULE folder_module_;
+ FuncPtr folder_path_func_;
+};
+
+boost::scoped_ptr<GetFolderPath> folder_path;
+
+#endif
+
} // namespace anon
@@ -129,6 +156,8 @@ Package::Package(string const & command_
string const & command_line_user_support_dir)
: explicit_user_support_dir_(false)
{
+ folder_path.reset(new GetFolderPath);
+
home_dir_ = get_home_dir();
temp_dir_ = get_temp_dir();
document_dir_ = get_document_dir(home_dir_);
@@ -153,6 +182,8 @@ Package::Package(string const & command_
get_user_support_dir(default_user_support_dir,
command_line_user_support_dir);
+ folder_path.reset();
+
lyxerr[Debug::INIT]
<< "<package>\n"
<< "\tbinary_dir " << binary_dir() << '\n'
@@ -186,15 +217,61 @@ string const relative_locale_dir();
string const relative_system_support_dir();
+// If we use a 'lazy' lyxerr in the hope of setting the locale before
+// printing any messages, then we should ensure that it is flushed first.
+void bail_out()
+{
+#ifndef CXX_GLOBAL_CSTD
+ using std::exit;
+#endif
+ exit(1);
+}
+
#if defined (USE_WINDOWS_PACKAGING)
+
+GetFolderPath::GetFolderPath()
+ : folder_module_(0),
+ folder_path_func_(0)
+{
+ folder_module_ = LoadLibrary("shfolder.dll");
+ if (!folder_module_) {
+ lyxerr << "Unable to load shfolder.dll\nPlease install."
+ << std::endl;
+ bail_out();
+ }
+
+ folder_path_func_ = (FuncPtr) ::GetProcAddress(folder_module_, "SHGetFolderPathA");
+ if (folder_path_func_ == 0) {
+ lyxerr << "Unable to find SHGetFolderPathA in shfolder.dll\n"
+ "Don't know how to proceed. Sorry."
+ << std::endl;
+ bail_out();
+ }
+}
+
+GetFolderPath::~GetFolderPath()
+{
+ if (folder_module_)
+ FreeLibrary(folder_module_);
+}
+
+
+HRESULT GetFolderPath::operator()(HWND a, int b, HANDLE c, DWORD d, LPCSTR e) const
+{
+ return (folder_path_func_)(a, b, c, d, e);
+}
+
+
// Given a folder ID, returns the folder name (in unix-style format).
// Eg CSIDL_PERSONAL -> "C:/Documents and Settings/USERNAME/My Documents"
string const win32_folder_path(int folder_id)
{
- char folder_path[PATH_MAX + 1];
- if (SUCCEEDED(SHGetFolderPath(0, folder_id, 0,
- SHGFP_TYPE_CURRENT, folder_path)))
+ BOOST_ASSERT(folder_path.get());
+ GetFolderPath const & gfp = *folder_path;
+
+ char folder_path[PATH_MAX];
+ if (SUCCEEDED(gfp(0, folder_id, 0, SHGFP_TYPE_CURRENT, folder_path)))
return os::internal_path(folder_path);
return string();
}
@@ -315,9 +392,9 @@ string const get_temp_dir()
{
#if defined (USE_WINDOWS_PACKAGING)
// Typical example: C:/TEMP/.
- char path[PATH_MAX + 1];
+ char path[PATH_MAX];
GetTempPath(PATH_MAX, path);
- GetLongPathName(path, path, PATH_MAX + 1);
+ GetLongPathName(path, path, PATH_MAX);
return os::internal_path(path);
#else // Posix-like.
return "/tmp";
@@ -325,17 +402,6 @@ string const get_temp_dir()
}
-// If we use a 'lazy' lyxerr in the hope of setting the locale before
-// printing any messages, then we should ensure that it is flushed first.
-void bail_out()
-{
-#ifndef CXX_GLOBAL_CSTD
- using std::exit;
-#endif
- exit(1);
-}
-
-
// Extracts the absolute path from the foo of "-sysdir foo" or "-userdir foo"
string const abs_path_from_command_line(string const & command_line)
{
@@ -351,10 +417,16 @@ string const abs_path_from_command_line(
string const get_binary_path(string const & exe)
{
#if defined (USE_WINDOWS_PACKAGING)
+ // Windows 2000 and earlier can give us DOS-style 8.3 file names
+ // when a .lyx file is opened by double clicking on it.
+ char exe_cstr[PATH_MAX];
+ bool const success = GetLongPathName(exe.c_str(), exe_cstr, PATH_MAX);
+ string const exe_str = success ? exe_cstr : exe;
+
// The executable may have been invoked either with or
// without the .exe extension.
// Ensure that it is present.
- string const as_internal_path = os::internal_path(exe);
+ string const as_internal_path = os::internal_path(exe_str);
string const exe_path = suffixIs(as_internal_path, ".exe") ?
as_internal_path : as_internal_path + ".exe";
#else
@@ -602,7 +674,7 @@ string const get_default_user_support_di
if (error_code != 0)
return string();
- char store[PATH_MAX + 1];
+ char store[PATH_MAX];
OSStatus const status_code =
FSRefMakePath(&fsref,
reinterpret_cast<UInt8*>(store), PATH_MAX);
Index: src/frontends/qt2/QWorkArea.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/qt2/QWorkArea.C,v
retrieving revision 1.11.2.3
diff -u -p -r1.11.2.3 QWorkArea.C
--- src/frontends/qt2/QWorkArea.C 18 Jul 2005 00:00:10 -0000 1.11.2.3
+++ src/frontends/qt2/QWorkArea.C 8 Sep 2005 22:04:59 -0000
@@ -38,6 +38,27 @@
#include <Carbon/Carbon.h>
#endif
+#ifdef Q_OS_WIN
+/*
+ * MinGW's version of winver.h contains this comment:
+ *
+ * If you need Win32 API features newer the Win95 and WinNT then you must
+ * define WINVER before including windows.h or any other method of including
+ * the windef.h header.
+ *
+ * GetLongPathNameA requires WINVER == 0x0500.
+ *
+ * It doesn't matter if the Windows version is older than this because the
+ * function will compile but will fail at run time. See
+ * http://msdn.microsoft.com/library/en-us/mslu/winprog/microsoft_layer_for_unicode_apis_with_limited_support.asp
+ */
+# if defined(__MINGW32__)
+# define WINVER 0x0500
+# endif
+
+# include <windows.h>
+#endif
+
#include <cmath>
#include <cctype>
@@ -234,7 +255,18 @@ void QWorkArea::dropEvent(QDropEvent* ev
<< endl;
for (QStringList::Iterator i = files.begin();
i!=files.end(); ++i) {
+#ifdef Q_OS_WIN
+ // Windows 2000 and below tend to give us
+ // DOS-style 8.3 file names.
+ char path[PATH_MAX];
+ bool const success =
+ GetLongPathName(fromqstr(*i).c_str(), path, PATH_MAX);
+ string const file = success ?
+ os::internal_path(path) :
+ os::internal_path(fromqstr(*i));;
+#else
string const file = os::internal_path(fromqstr(*i));
+#endif
viewDispatch(FuncRequest(LFUN_FILE_OPEN, file));
}
}