From 73e1a6a470f6a01fe2ef8e9f4355f8e15abbfbe3 Mon Sep 17 00:00:00 2001 From: Angus Leeming Date: Fri, 30 Sep 2005 12:24:50 +0000 Subject: [PATCH] Support for Win98 and earlier. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@10501 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/support/ChangeLog | 11 +++ src/support/Makefile.am | 3 +- src/support/os_win32.C | 145 +++++++++++++++++++++++++++++++++++++-- src/support/os_win32.h | 84 +++++++++++++++++++++++ src/support/package.C.in | 55 +++------------ 5 files changed, 245 insertions(+), 53 deletions(-) create mode 100644 src/support/os_win32.h diff --git a/src/support/ChangeLog b/src/support/ChangeLog index 7b23d465de..a399cb254e 100644 --- a/src/support/ChangeLog +++ b/src/support/ChangeLog @@ -1,3 +1,14 @@ +2005-09-30 Angus Leeming + + * 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 * Makefile.am: use the Windows-friendly LYX_ABS_INSTALLED_LOCALEDIR diff --git a/src/support/Makefile.am b/src/support/Makefile.am index 1e9187d753..22fbb594d0 100644 --- a/src/support/Makefile.am +++ b/src/support/Makefile.am @@ -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 diff --git a/src/support/os_win32.C b/src/support/os_win32.C index d62b0f4f39..d80c2aa1fa 100644 --- a/src/support/os_win32.C +++ b/src/support/os_win32.C @@ -14,14 +14,65 @@ #include +/* The GetLongPathNameA function declaration in + * under MinGW or Cygwin is protected + * by the WINVER macro which is defined in + * + * SHGFP_TYPE_CURRENT is defined in 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 +# 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 + +#include +#include + +#include + #include + +/* 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 +# undef COMPILE_NEWAPIS_STUBS +# undef WANT_GETLONGPATHNAME_WRAPPER +#endif + #include #include // _getdrive +#include // 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 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(::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 diff --git a/src/support/os_win32.h b/src/support/os_win32.h new file mode 100644 index 0000000000..7bb2800737 --- /dev/null +++ b/src/support/os_win32.h @@ -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 + +#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 + + +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 diff --git a/src/support/package.C.in b/src/support/package.C.in index c205d05c91..d9c2758893 100644 --- a/src/support/package.C.in +++ b/src/support/package.C.in @@ -24,7 +24,10 @@ #include "support/lstrings.h" #include "support/os.h" -#include +#if defined (USE_WINDOWS_PACKAGING) +# include "support/os_win32.h" +#endif + #include #include @@ -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 -# include // SHGetFolderPath - - // Needed for MinGW: -# ifndef SHGFP_TYPE_CURRENT -# define SHGFP_TYPE_CURRENT 0 -# endif - #elif defined (USE_MACOSX_PACKAGING) # include // 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. -- 2.39.2