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));
     }
 }
Exemple #6
0
// 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));
}