Support for Win98 and earlier.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@10501 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Angus Leeming 2005-09-30 12:24:50 +00:00
parent 19e1292d73
commit 73e1a6a470
5 changed files with 245 additions and 53 deletions

View File

@ -1,3 +1,14 @@
2005-09-30 Angus Leeming <leeming@lyx.org>
* os_win32.h: new file, providing a public and portable interface
to the SHGetFolderPath function for older flavours of Windows.
* os_win32.C: tighten up code. Define the ShGetFolder class. Make
use of Microsoft's NewAPIs.h if available to provide us with
runtime support for Windows 95.
(internal_path): always pass the path through GetLongPathName.
* package.C.in: move lots of stuff out and into os_win32.C.
2005-09-29 Angus Leeming <leeming@lyx.org>
* Makefile.am: use the Windows-friendly LYX_ABS_INSTALLED_LOCALEDIR

View File

@ -4,7 +4,8 @@ SUBDIRS = . tests
CLEANFILES += $(BUILT_SOURCES)
EXTRA_DIST = package.C.in pch.h os_cygwin.C os_os2.C os_unix.C os_win32.C
EXTRA_DIST = package.C.in pch.h \
os_cygwin.C os_os2.C os_unix.C os_win32.C os_win32.h
noinst_LTLIBRARIES = libsupport.la

View File

@ -14,14 +14,65 @@
#include <config.h>
/* The GetLongPathNameA function declaration in
* <winbase.h> under MinGW or Cygwin is protected
* by the WINVER macro which is defined in <windef.h>
*
* SHGFP_TYPE_CURRENT is defined in <shlobj.h> for __W32API_VERSION >= 3.2
* where it is protected by _WIN32_IE.
* It is missing in earlier versions of the MinGW w32api headers.
*/
#if defined(__MINGW32__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
# include <w32api.h>
# define WINVER 0x0500
# define _WIN32_IE 0x0500
#endif
#include "support/os.h"
#include "support/os_win32.h"
#include "support/lstrings.h"
#include "debug.h"
#include <boost/assert.hpp>
#include <cstdlib>
#include <vector>
#include <string>
#include <windows.h>
/* The GetLongPathName macro may be defined on the compiling machine,
* but we must use a bit of trickery if the resulting executable is
* to run on a Win95 machine.
* Fortunately, Microsoft provide the trickery. All we need is the
* NewAPIs.h header file, available for download from Microsoft as
* part of the Platform SDK.
*/
#if defined (HAVE_NEWAPIS_H)
// This should be defined already to keep Boost.Filesystem happy.
# if !defined (WANT_GETFILEATTRIBUTESEX_WRAPPER)
# error Expected WANT_GETFILEATTRIBUTESEX_WRAPPER to be defined!
# endif
# define WANT_GETLONGPATHNAME_WRAPPER 1
# define COMPILE_NEWAPIS_STUBS
# include <NewAPIs.h>
# undef COMPILE_NEWAPIS_STUBS
# undef WANT_GETLONGPATHNAME_WRAPPER
#endif
#include <io.h>
#include <direct.h> // _getdrive
#include <shlobj.h> // SHGetFolderPath
// Needed by older versions of MinGW.
#if defined (__W32API_MAJOR_VERSION) && \
defined (__W32API_MINOR_VERSION) && \
(__W32API_MAJOR_VERSION < 3 || \
__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 2)
# define SHGFP_TYPE_CURRENT 0
#endif
using std::endl;
using std::string;
@ -31,7 +82,7 @@ namespace lyx {
namespace support {
namespace os {
void os::init(int /* argc */, char * argv[])
void init(int /* argc */, char * argv[])
{
/* Note from Angus, 17 Jan 2005:
*
@ -153,13 +204,30 @@ string external_path(string const & p)
}
// (Claus H.) Parsing the latex log file in an Win32 environment all
// files are mentioned in Win32/DOS syntax. Because LyX uses the dep file
// entries to check if any file has been changed we must retranslate
// the Win32/DOS pathnames into Cygwin pathnames.
namespace {
string const get_long_path(string const & short_path)
{
std::vector<char> long_path(PATH_MAX);
DWORD result = GetLongPathName(short_path.c_str(),
&long_path[0], long_path.size());
if (result > long_path.size()) {
long_path.resize(result);
result = GetLongPathName(short_path.c_str(),
&long_path[0], long_path.size());
BOOST_ASSERT(result <= long_path.size());
}
return (result == 0) ? short_path : &long_path[0];
}
} // namespace anon
string internal_path(string const & p)
{
return subst(p, "\\", "/");
return subst(get_long_path(p), "\\", "/");
}
@ -211,6 +279,71 @@ char path_separator()
void cygwin_path_fix(bool)
{}
namespace {
void bail_out()
{
#ifndef CXX_GLOBAL_CSTD
using std::exit;
#endif
exit(1);
}
} // namespace anon
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_ = reinterpret_cast<function_pointer>(::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_);
}
// Given a folder ID, returns the folder name (in unix-style format).
// Eg CSIDL_PERSONAL -> "C:/Documents and Settings/USERNAME/My Documents"
string const GetFolderPath::operator()(folder_id _id) const
{
char folder_path[PATH_MAX];
int id = 0;
switch (_id) {
case PERSONAL:
id = CSIDL_PERSONAL;
break;
case APPDATA:
id = CSIDL_APPDATA;
break;
default:
BOOST_ASSERT(false);
}
HRESULT const result = (folder_path_func_)(0, id, 0,
SHGFP_TYPE_CURRENT,
folder_path);
return (result == 0) ? os::internal_path(folder_path) : string();
}
} // namespace os
} // namespace support
} // namespace lyx

84
src/support/os_win32.h Normal file
View File

@ -0,0 +1,84 @@
// -*- C++ -*-
/**
* \file os_win32.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Angus Leeming
*
* Full author contact details are available in file CREDITS.
*
* These classes should be used only on Windows machines.
*/
#ifndef OS_WIN32_H
#define OS_WIN32_H
#include <string>
#if !defined(_WIN32)
# error os_win32.h should be compiled only under Windows.
#endif
/* The GetLongPathNameA function declaration in
* winbase.h under MinGW or Cygwin is protected
* by the WINVER macro which is defined in windef.h
*
* We need to #include this file to make available the
* DWORD, HMODULE et al. typedefs, so check WINVER now.
*
* Note: __CYGWIN__ can be defined here if building in _WIN32 mode.
*/
#if defined(__MINGW32__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
# if !defined(WINVER) || WINVER < 0x0500
# error WINVER must be >= 0x0500
# endif
#endif
#include <windef.h>
namespace lyx {
namespace support {
namespace os {
/** 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.
*
* shfolder.dll is loaded dynamically in the constructor. If loading
* fails or if the .dll is found not to contain SHGetFolderPathA then
* the program exits immediately. Otherwise, the .dll is unloaded in
* the destructor
*
* The class makes SHGetFolderPath available through its function operator.
* It will work on all versions of Windows >= Win95.
*/
class GetFolderPath {
public:
enum folder_id {
/// CSIDL_PERSONAL
PERSONAL,
/// CSIDL_APPDATA
APPDATA
};
GetFolderPath();
~GetFolderPath();
/** Wrapper for SHGetFolderPathA, returning
* the path asscociated with @c id.
*/
std::string const operator()(folder_id id) const;
private:
typedef HRESULT (__stdcall * function_pointer)(HWND, int, HANDLE, DWORD, LPCSTR);
HMODULE folder_module_;
function_pointer folder_path_func_;
};
} // namespace os
} // namespace support
} // namespace lyx
#endif // OS_WIN32_H

View File

@ -24,7 +24,10 @@
#include "support/lstrings.h"
#include "support/os.h"
#include <boost/assert.hpp>
#if defined (USE_WINDOWS_PACKAGING)
# include "support/os_win32.h"
#endif
#include <boost/filesystem/operations.hpp>
#include <boost/tuple/tuple.hpp>
@ -38,32 +41,7 @@
#endif
#if defined (USE_WINDOWS_PACKAGING)
/*
* 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>
# include <shlobj.h> // SHGetFolderPath
// Needed for MinGW:
# ifndef SHGFP_TYPE_CURRENT
# define SHGFP_TYPE_CURRENT 0
# endif
#elif defined (USE_MACOSX_PACKAGING)
# include <CoreServices/CoreServices.h> // FSFindFolder, FSRefMakePath
#endif
@ -234,20 +212,6 @@ string const relative_locale_dir();
string const relative_system_support_dir();
#if defined (USE_WINDOWS_PACKAGING)
// 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)))
return os::internal_path(folder_path);
return string();
}
#endif
std::string const
get_build_support_dir(std::string const & binary_dir,
exe_build_dir_to_top_build_dir top_build_dir_location)
@ -325,7 +289,8 @@ string const get_document_dir(string const & home_dir)
{
#if defined (USE_WINDOWS_PACKAGING)
(void)home_dir; // Silence warning about unused variable.
return win32_folder_path(CSIDL_PERSONAL);
os::GetFolderPath win32_folder_path;
return win32_folder_path(os::GetFolderPath::PERSONAL);
#else // Posix-like.
return home_dir;
#endif
@ -379,9 +344,8 @@ 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);
return os::internal_path(path);
#else // Posix-like.
return "/tmp";
@ -389,8 +353,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
@ -631,7 +593,8 @@ string const get_default_user_support_dir(string const & home_dir)
#if defined (USE_WINDOWS_PACKAGING)
(void)home_dir; // Silence warning about unused variable.
return AddPath(win32_folder_path(CSIDL_APPDATA), PACKAGE);
os::GetFolderPath win32_folder_path;
return AddPath(win32_folder_path(os::GetFolderPath::APPDATA), PACKAGE);
#elif defined (USE_MACOSX_PACKAGING)
(void)home_dir; // Silence warning about unused variable.