static void ParseCommandLine(WCHAR *cmdLine) { WStrVec argList; ParseCmdLine(cmdLine, argList); #define is_arg(param) str::EqI(arg + 1, TEXT(param)) #define is_arg_with_param(param) (is_arg(param) && i < argList.Count() - 1) // skip the first arg (exe path) for (size_t i = 1; i < argList.Count(); i++) { WCHAR *arg = argList.At(i); if ('-' != *arg && '/' != *arg) continue; if (is_arg("s")) gGlobalData.silent = true; else if (is_arg_with_param("d")) str::ReplacePtr(&gGlobalData.installDir, argList.At(++i)); #ifndef BUILD_UNINSTALLER else if (is_arg("register")) gGlobalData.registerAsDefault = true; else if (is_arg_with_param("opt")) { WCHAR *opts = argList.At(++i); str::ToLower(opts); str::TransChars(opts, L" ;", L",,"); WStrVec optlist; optlist.Split(opts, L",", true); if (optlist.Contains(L"pdffilter")) gGlobalData.installPdfFilter = true; if (optlist.Contains(L"pdfpreviewer")) gGlobalData.installPdfPreviewer = true; // uninstall the deprecated browser plugin if it's not // explicitly listed (only applies if the /opt flag is used) if (!optlist.Contains(L"plugin")) gGlobalData.keepBrowserPlugin = false; } else if (is_arg("x")) { gGlobalData.justExtractFiles = true; // silently extract files to the current directory (if /d isn't used) gGlobalData.silent = true; if (!gGlobalData.installDir) str::ReplacePtr(&gGlobalData.installDir, L"."); } else if (is_arg("autoupdate")) { gGlobalData.autoUpdate = true; } #endif else if (is_arg("h") || is_arg("help") || is_arg("?")) gGlobalData.showUsageAndQuit = true; #ifdef ENABLE_CRASH_TESTING else if (is_arg("crash")) { // will induce crash when 'Install' button is pressed // for testing crash handling gForceCrash = true; } #endif } }
static void CALLBACK ReadDirectoryChangesNotification(DWORD errCode, DWORD bytesTransfered, LPOVERLAPPED overlapped) { ScopedCritSec cs(&g_threadCritSec); OverlappedEx *over = (OverlappedEx*)overlapped; WatchedDir* wd = (WatchedDir*)over->data; lf(L"ReadDirectoryChangesNotification() dir: %s, numBytes: %d", wd->dirPath, (int)bytesTransfered); CrashIf(wd != wd->overlapped.data); if (errCode == ERROR_OPERATION_ABORTED) { lf(" ERROR_OPERATION_ABORTED"); DeleteWatchedDir(wd); InterlockedDecrement(&gRemovalsPending); return; } // This might mean overflow? Not sure. if (!bytesTransfered) return; FILE_NOTIFY_INFORMATION *notify = (FILE_NOTIFY_INFORMATION*)wd->buf; // collect files that changed, removing duplicates WStrVec changedFiles; for (;;) { ScopedMem<WCHAR> fileName(str::DupN(notify->FileName, notify->FileNameLength / sizeof(WCHAR))); // files can get updated either by writing to them directly or // by writing to a .tmp file first and then moving that file in place // (the latter only yields a RENAMED action with the expected file name) if (notify->Action == FILE_ACTION_MODIFIED || notify->Action == FILE_ACTION_RENAMED_NEW_NAME) { if (!changedFiles.Contains(fileName)) { lf(L"ReadDirectoryChangesNotification() FILE_ACTION_MODIFIED, for '%s'", fileName); changedFiles.Append(fileName.StealData()); } else { lf(L"ReadDirectoryChangesNotification() eliminating duplicate notification for '%s'", fileName); } } else { lf(L"ReadDirectoryChangesNotification() action=%d, for '%s'", (int)notify->Action, fileName); } // step to the next entry if there is one DWORD nextOff = notify->NextEntryOffset; if (!nextOff) break; notify = (FILE_NOTIFY_INFORMATION *)((char*)notify + nextOff); } StartMonitoringDirForChanges(wd); for (const WCHAR *f : changedFiles) { NotifyAboutFile(wd, f); } }
static void CALLBACK ReadDirectoryChangesNotification(DWORD errCode, DWORD bytesTransfered, LPOVERLAPPED overlapped) { ScopedCritSec cs(&g_threadCritSec); OverlappedEx *over = (OverlappedEx*)overlapped; WatchedDir* wd = (WatchedDir*)over->data; lf(L"ReadDirectoryChangesNotification() dir: %s, numBytes: %d", wd->dirPath, (int)bytesTransfered); CrashIf(wd != wd->overlapped.data); if (errCode == ERROR_OPERATION_ABORTED) { lf(" ERROR_OPERATION_ABORTED"); DeleteWatchedDir(wd); return; } // This might mean overflow? Not sure. if (!bytesTransfered) return; FILE_NOTIFY_INFORMATION *notify = (FILE_NOTIFY_INFORMATION*)wd->buf; // collect files that changed, removing duplicates WStrVec changedFiles; for (;;) { WCHAR *fileName = str::DupN(notify->FileName, notify->FileNameLength / sizeof(WCHAR)); if (notify->Action == FILE_ACTION_MODIFIED) { if (!changedFiles.Contains(fileName)) { lf(L"ReadDirectoryChangesNotification() FILE_ACTION_MODIFIED, for '%s'", fileName); changedFiles.Append(fileName); fileName = NULL; } else { lf(L"ReadDirectoryChangesNotification() eliminating duplicate notification for '%s'", fileName); } } else { lf(L"ReadDirectoryChangesNotification() action=%d, for '%s'", (int)notify->Action, fileName); } free(fileName); // step to the next entry if there is one DWORD nextOff = notify->NextEntryOffset; if (!nextOff) break; notify = (FILE_NOTIFY_INFORMATION *)((char*)notify + nextOff); } StartMonitoringDirForChanges(wd); for (WCHAR **f = changedFiles.IterStart(); f; f = changedFiles.IterNext()) { NotifyAboutFile(wd, *f); } }
static WCHAR *FormatPdfFileStructure(Controller *ctrl) { ScopedMem<WCHAR> fstruct(ctrl->GetProperty(Prop_PdfFileStructure)); if (str::IsEmpty(fstruct.Get())) return nullptr; WStrVec parts; parts.Split(fstruct, L",", true); WStrVec props; if (parts.Contains(L"linearized")) props.Push(str::Dup(_TR("Fast Web View"))); if (parts.Contains(L"tagged")) props.Push(str::Dup(_TR("Tagged PDF"))); if (parts.Contains(L"PDFX")) props.Push(str::Dup(L"PDF/X (ISO 15930)")); if (parts.Contains(L"PDFA1")) props.Push(str::Dup(L"PDF/A (ISO 19005)")); if (parts.Contains(L"PDFE1")) props.Push(str::Dup(L"PDF/E (ISO 24517)")); return props.Join(L", "); }
FileExistenceChecker() { DisplayState *state; for (size_t i = 0; i < 2 * FILE_HISTORY_MAX_RECENT && (state = gFileHistory.Get(i)) != NULL; i++) { if (!state->isMissing) paths.Append(str::Dup(state->filePath)); } // add missing paths from the list of most frequently opened documents Vec<DisplayState *> frequencyList; gFileHistory.GetFrequencyOrder(frequencyList); for (size_t i = 0; i < 2 * FILE_HISTORY_MAX_FREQUENT && i < frequencyList.Count(); i++) { state = frequencyList.At(i); if (!paths.Contains(state->filePath)) paths.Append(str::Dup(state->filePath)); } }
// verify that all registry entries that need to be set in order to associate // Sumatra with .pdf files exist and have the right values bool IsExeAssociatedWithPdfExtension() { // this one doesn't have to exist but if it does, it must be APP_NAME_STR ScopedMem<WCHAR> tmp(ReadRegStr(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT, L"Progid")); if (tmp && !str::Eq(tmp, APP_NAME_STR)) return false; // this one doesn't have to exist but if it does, it must be APP_NAME_STR.exe tmp.Set(ReadRegStr(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT, L"Application")); if (tmp && !str::EqI(tmp, APP_NAME_STR L".exe")) return false; // this one doesn't have to exist but if it does, it must be APP_NAME_STR tmp.Set(ReadRegStr(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT L"\\UserChoice", L"Progid")); if (tmp && !str::Eq(tmp, APP_NAME_STR)) return false; // HKEY_CLASSES_ROOT\.pdf default key must exist and be equal to APP_NAME_STR tmp.Set(ReadRegStr(HKEY_CLASSES_ROOT, L".pdf", NULL)); if (!str::Eq(tmp, APP_NAME_STR)) return false; // HKEY_CLASSES_ROOT\SumatraPDF\shell\open default key must be: open tmp.Set(ReadRegStr(HKEY_CLASSES_ROOT, APP_NAME_STR L"\\shell", NULL)); if (!str::EqI(tmp, L"open")) return false; // HKEY_CLASSES_ROOT\SumatraPDF\shell\open\command default key must be: "${exe_path}" "%1" tmp.Set(ReadRegStr(HKEY_CLASSES_ROOT, APP_NAME_STR L"\\shell\\open\\command", NULL)); if (!tmp) return false; WStrVec argList; ParseCmdLine(tmp, argList); ScopedMem<WCHAR> exePath(GetExePath()); if (!exePath || !argList.Contains(L"%1") || !str::Find(tmp, L"\"%1\"")) return false; return path::IsSame(exePath, argList.At(0)); }