X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fcross_windows.cc;h=324b8cd8bd5cab03e3eb59266f7fbb2ea12f499a;hb=47d83b296248119d04b9226fd51a67e2fd3faac5;hp=04ee26271b7a5c80595c1ce87e38b87a2de5fad1;hpb=3339d3bce70afe9ae2ca10e9fcfc4b54b748fbf4;p=dcpomatic.git diff --git a/src/lib/cross_windows.cc b/src/lib/cross_windows.cc index 04ee26271..324b8cd8b 100644 --- a/src/lib/cross_windows.cc +++ b/src/lib/cross_windows.cc @@ -19,6 +19,8 @@ */ +#define UNICODE 1 + #include "cross.h" #include "compose.hpp" #include "log.h" @@ -26,6 +28,7 @@ #include "config.h" #include "exceptions.h" #include "dcpomatic_assert.h" +#include "util.h" #include #include extern "C" { @@ -41,7 +44,9 @@ extern "C" { #include #undef DATADIR #include +#include #include +#include #include #include #include @@ -205,16 +210,9 @@ resources_path () boost::filesystem::path -xsd_path () +libdcp_resources_path () { - return directory_containing_executable().parent_path() / "xsd"; -} - - -boost::filesystem::path -tags_path () -{ - return directory_containing_executable().parent_path() / "tags"; + return resources_path (); } @@ -234,6 +232,44 @@ disk_writer_path () #endif +/** Windows can't "by default" cope with paths longer than 260 characters, so if you pass such a path to + * any boost::filesystem method it will fail. There is a "fix" for this, which is to prepend + * the string \\?\ to the path. This will make it work, so long as: + * - the path is absolute. + * - the path only uses backslashes. + * - individual path components are "short enough" (probably less than 255 characters) + * + * See https://www.boost.org/doc/libs/1_57_0/libs/filesystem/doc/reference.html under + * "Warning: Long paths on Windows" for some details. + * + * Our fopen_boost uses this method to get this fix, but any other calls to boost::filesystem + * will not unless this method is explicitly called to pre-process the pathname. + */ +boost::filesystem::path +fix_long_path (boost::filesystem::path long_path) +{ + using namespace boost::filesystem; + + if (boost::algorithm::starts_with(long_path.string(), "\\\\")) { + /* This could mean it starts with \\ (i.e. a SMB path) or \\?\ (a long path) + * or a variety of other things... anyway, we'll leave it alone. + */ + return long_path; + } + + /* We have to make the path canonical but we can't call canonical() on the long path + * as it will fail. So we'll sort of do it ourselves (possibly badly). + */ + path fixed = "\\\\?\\"; + if (long_path.is_absolute()) { + fixed += long_path.make_preferred(); + } else { + fixed += boost::filesystem::current_path() / long_path.make_preferred(); + } + return fixed; +} + + /* Apparently there is no way to create an ofstream using a UTF-8 filename under Windows. We are hence reduced to using fopen with this wrapper. @@ -242,8 +278,8 @@ FILE * fopen_boost (boost::filesystem::path p, string t) { wstring w (t.begin(), t.end()); - /* c_str() here should give a UTF-16 string */ - return _wfopen (p.c_str(), w.c_str ()); + /* c_str() on fixed here should give a UTF-16 string */ + return _wfopen (fix_long_path(p).c_str(), w.c_str()); } @@ -356,7 +392,17 @@ maybe_open_console () boost::filesystem::path home_directory () { - return boost::filesystem::path(getenv("HOMEDRIVE")) / boost::filesystem::path(getenv("HOMEPATH")); + PWSTR wide_path; + auto result = SHGetKnownFolderPath(FOLDERID_Documents, 0, nullptr, &wide_path); + + if (result != S_OK) { + CoTaskMemFree(wide_path); + return boost::filesystem::path("c:\\"); + } + + auto path = wchar_to_utf8(wide_path); + CoTaskMemFree(wide_path); + return path; } @@ -634,11 +680,14 @@ Drive::unmount () boost::filesystem::path -config_path () +config_path (optional version) { boost::filesystem::path p; p /= g_get_user_config_dir (); p /= "dcpomatic2"; + if (version) { + p /= *version; + } return p; } @@ -658,3 +707,13 @@ dcpomatic::get_process_id () return dcp::raw_convert(GetCurrentProcessId()); } + +bool +show_in_file_manager (boost::filesystem::path, boost::filesystem::path select) +{ + std::wstringstream args; + args << "/select," << select; + auto const r = ShellExecute (0, L"open", L"explorer.exe", args.str().c_str(), 0, SW_SHOWDEFAULT); + return (reinterpret_cast(r) <= 32); +} +