X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fcross_windows.cc;h=9181b6c8abf1deb8861a21c65b3db63d4d62a883;hb=3ffd0163026be24e5373e0674c3301ed37546e44;hp=a7e7bdd555255830550915a00c4524048e03cc94;hpb=c453583807bdb2b26bc5bfb080a90c32bc1260f4;p=dcpomatic.git diff --git a/src/lib/cross_windows.cc b/src/lib/cross_windows.cc index a7e7bdd55..9181b6c8a 100644 --- a/src/lib/cross_windows.cc +++ b/src/lib/cross_windows.cc @@ -29,6 +29,8 @@ #include "exceptions.h" #include "dcpomatic_assert.h" #include "util.h" +#include +#include #include #include extern "C" { @@ -43,10 +45,11 @@ extern "C" { #include #include #undef DATADIR -#include -#include -#include #include +#include +#include +#include +#include #include #include #include @@ -123,37 +126,51 @@ cpu_info () void -run_ffprobe (boost::filesystem::path content, boost::filesystem::path out) +run_ffprobe(boost::filesystem::path content, boost::filesystem::path out, bool err, string args) { SECURITY_ATTRIBUTES security; security.nLength = sizeof (security); security.bInheritHandle = TRUE; security.lpSecurityDescriptor = 0; - HANDLE child_stderr_read; - HANDLE child_stderr_write; - if (!CreatePipe (&child_stderr_read, &child_stderr_write, &security, 0)) { + HANDLE child_out_read; + HANDLE child_out_write; + if (!CreatePipe(&child_out_read, &child_out_write, &security, 0)) { LOG_ERROR_NC ("ffprobe call failed (could not CreatePipe)"); return; } + if (!SetHandleInformation(child_out_read, HANDLE_FLAG_INHERIT, 0)) { + LOG_ERROR_NC("ffprobe call failed (could not SetHandleInformation)"); + return; + } + wchar_t dir[512]; MultiByteToWideChar (CP_UTF8, 0, directory_containing_executable().string().c_str(), -1, dir, sizeof(dir)); STARTUPINFO startup_info; ZeroMemory (&startup_info, sizeof (startup_info)); startup_info.cb = sizeof (startup_info); - startup_info.hStdError = child_stderr_write; + if (err) { + startup_info.hStdError = child_out_write; + } else { + startup_info.hStdOutput = child_out_write; + } startup_info.dwFlags |= STARTF_USESTDHANDLES; wchar_t command[512]; - wcscpy (command, L"ffprobe.exe \""); + wcscpy(command, L"ffprobe.exe "); + + wchar_t tmp[512]; + MultiByteToWideChar(CP_UTF8, 0, args.c_str(), -1, tmp, sizeof(tmp)); + wcscat(command, tmp); + + wcscat(command, L" \""); - wchar_t file[512]; - MultiByteToWideChar (CP_UTF8, 0, content.string().c_str(), -1, file, sizeof(file)); - wcscat (command, file); + MultiByteToWideChar(CP_UTF8, 0, dcp::filesystem::canonical(content).make_preferred().string().c_str(), -1, tmp, sizeof(tmp)); + wcscat(command, tmp); - wcscat (command, L"\""); + wcscat(command, L"\""); PROCESS_INFORMATION process_info; ZeroMemory (&process_info, sizeof (process_info)); @@ -162,29 +179,29 @@ run_ffprobe (boost::filesystem::path content, boost::filesystem::path out) return; } - auto o = fopen_boost (out, "w"); + dcp::File o(out, "w"); if (!o) { LOG_ERROR_NC (N_("ffprobe call failed (could not create output file)")); return; } - CloseHandle (child_stderr_write); + CloseHandle(child_out_write); while (true) { char buffer[512]; DWORD read; - if (!ReadFile(child_stderr_read, buffer, sizeof(buffer), &read, 0) || read == 0) { + if (!ReadFile(child_out_read, buffer, sizeof(buffer), &read, 0) || read == 0) { break; } - fwrite (buffer, read, 1, o); + o.write(buffer, read, 1); } - fclose (o); + o.close(); WaitForSingleObject (process_info.hProcess, INFINITE); CloseHandle (process_info.hProcess); CloseHandle (process_info.hThread); - CloseHandle (child_stderr_read); + CloseHandle(child_out_read); } @@ -232,64 +249,6 @@ 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. -*/ -FILE * -fopen_boost (boost::filesystem::path p, string t) -{ - wstring w (t.begin(), t.end()); - /* c_str() on fixed here should give a UTF-16 string */ - return _wfopen (fix_long_path(p).c_str(), w.c_str()); -} - - -int -dcpomatic_fseek (FILE* stream, int64_t offset, int whence) -{ - return _fseeki64 (stream, offset, whence); -} - - void Waker::nudge () { @@ -353,10 +312,9 @@ static string wchar_to_utf8 (wchar_t const * s) { int const length = (wcslen(s) + 1) * 2; - char* utf8 = new char[length]; - WideCharToMultiByte (CP_UTF8, 0, s, -1, utf8, length, 0, 0); - string u (utf8); - delete[] utf8; + std::vector utf8(length); + WideCharToMultiByte (CP_UTF8, 0, s, -1, utf8.data(), length, 0, 0); + string u (utf8.data()); return u; } @@ -715,3 +673,17 @@ show_in_file_manager (boost::filesystem::path, boost::filesystem::path select) return (reinterpret_cast(r) <= 32); } + +ArgFixer::ArgFixer(int, char**) +{ + auto cmd_line = GetCommandLineW(); + auto wide_argv = CommandLineToArgvW(cmd_line, &_argc); + + _argv_strings.resize(_argc); + _argv = new char*[_argc]; + for (int i = 0; i < _argc; ++i) { + _argv_strings[i] = wchar_to_utf8(wide_argv[i]); + _argv[i] = const_cast(_argv_strings[i].c_str()); + } +} +