示例#1
0
static void EnumeratePrinters() {
    str::Str<WCHAR> output;

    PRINTER_INFO_5 *info5Arr = nullptr;
    DWORD bufSize = 0, printersCount;
    bool fOk = EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 5, nullptr,
                            bufSize, &bufSize, &printersCount);
    if (fOk || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
        info5Arr = (PRINTER_INFO_5 *)malloc(bufSize);
        fOk = EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 5,
                           (LPBYTE)info5Arr, bufSize, &bufSize, &printersCount);
    }
    if (!fOk || !info5Arr) {
        output.AppendFmt(L"Call to EnumPrinters failed with error %#x", GetLastError());
        MessageBox(nullptr, output.Get(), L"SumatraPDF - EnumeratePrinters", MB_OK | MB_ICONERROR);
        free(info5Arr);
        return;
    }
    ScopedMem<WCHAR> defName(GetDefaultPrinterName());
    for (DWORD i = 0; i < printersCount; i++) {
        const WCHAR *printerName = info5Arr[i].pPrinterName;
        const WCHAR *printerPort = info5Arr[i].pPortName;
        bool fDefault = str::Eq(defName, printerName);
        output.AppendFmt(L"%s (Port: %s, attributes: %#x%s)\n", printerName, printerPort,
                         info5Arr[i].Attributes, fDefault ? L", default" : L"");

        DWORD bins = DeviceCapabilities(printerName, printerPort, DC_BINS, nullptr, nullptr);
        DWORD binNames =
            DeviceCapabilities(printerName, printerPort, DC_BINNAMES, nullptr, nullptr);
        CrashIf(bins != binNames);
        if (0 == bins) {
            output.Append(L" - no paper bins available\n");
        } else if (bins == (DWORD)-1) {
            output.AppendFmt(L" - Call to DeviceCapabilities failed with error %#x\n",
                             GetLastError());
        } else {
            ScopedMem<WORD> binValues(AllocArray<WORD>(bins));
            DeviceCapabilities(printerName, printerPort, DC_BINS, (WCHAR *)binValues.Get(),
                               nullptr);
            ScopedMem<WCHAR> binNameValues(AllocArray<WCHAR>(24 * binNames));
            DeviceCapabilities(printerName, printerPort, DC_BINNAMES, binNameValues.Get(), nullptr);
            for (DWORD j = 0; j < bins; j++) {
                output.AppendFmt(L" - '%s' (%d)\n", binNameValues.Get() + 24 * j,
                                 binValues.Get()[j]);
            }
        }
    }
    free(info5Arr);
    MessageBox(nullptr, output.Get(), L"SumatraPDF - EnumeratePrinters",
               MB_OK | MB_ICONINFORMATION);
}
nsresult nsPrintOptions::_CreatePrintSettings(nsIPrintSettings **_retval)
{
  // does not initially ref count
  nsPrintSettings * printSettings = new nsPrintSettings();
  NS_ENSURE_TRUE(printSettings, NS_ERROR_OUT_OF_MEMORY);

  NS_ADDREF(*_retval = printSettings); // ref count

  nsXPIDLString printerName;
  nsresult rv = GetDefaultPrinterName(getter_Copies(printerName));
  NS_ENSURE_SUCCESS(rv, rv);
  (*_retval)->SetPrinterName(printerName.get());

  (void)InitPrintSettingsFromPrefs(*_retval, PR_FALSE,
                                   nsIPrintSettings::kInitSaveAll);

  return NS_OK;
}
示例#3
0
文件: io_printer.c 项目: VlaBst6/fbc
static int
fb_hPrinterBuildListDefault( FB_LIST *list, int iStartPort )
{
    char Buffer[32];
    int iPort = iStartPort - 1;
    char *printer_name = GetDefaultPrinterName( );

    if( printer_name!=NULL ) {
        if( fb_hListDevFindName( list, printer_name )==NULL ) {
            DEV_PRINTER_DEVICE* node;

            do {
                ++iPort;
                sprintf( Buffer, "LPT%d", iPort );
                node = fb_hListDevFindDevice( list, Buffer );
            } while( node!=NULL );

            fb_hListDevElemAlloc ( list, Buffer, printer_name );
        }
        free( printer_name );
    }

    return iPort + 1;
}
示例#4
0
文件: io_printer.c 项目: VlaBst6/fbc
int fb_PrinterOpen( DEV_LPT_INFO *devInfo, int iPort, const char *pszDevice )
{
    int result = fb_ErrorSetNum( FB_RTERROR_OK );
    const DEV_PRINTER_EMU_MODE *pFoundEmu = NULL;
    DWORD dwJob = 0;
    BOOL fResult;
    HANDLE hPrinter = NULL;
    HDC hDc = NULL;

		char *printer_name = NULL;
		char *doc_title = NULL;

		DEV_LPT_PROTOCOL *lpt_proto;
		if ( !fb_DevLptParseProtocol( &lpt_proto, pszDevice, strlen(pszDevice), TRUE ) )
		{
			if( lpt_proto!=NULL )
				free(lpt_proto);
      return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL );
		}

    /* Allow only valid emulation modes */
    if( *lpt_proto->emu!=0 ) {
        int i;
        for( i=0;
             i!=sizeof(aEmulationModes)/sizeof(aEmulationModes[0]);
             ++i )
        {
            const DEV_PRINTER_EMU_MODE *pEmu = aEmulationModes + i;
            if( strcasecmp( lpt_proto->emu, pEmu->pszId )==0 ) {
                pFoundEmu = pEmu;
                break;
            }
        }
        if( !pFoundEmu )
				{
					if( lpt_proto!=NULL )
						free(lpt_proto);
          return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL );
				}
    }

    if( iPort==0 ) {
      /* LPT:[PrinterName] */
			if( *lpt_proto->name )
			{
        printer_name = strdup( lpt_proto->name );
			} else {
				printer_name = GetDefaultPrinterName();
			}

    } else {
        /* LPTx: */
        FB_LIST dev_printer_devs;
        DEV_PRINTER_DEVICE* node;

        fb_hListDevInit( &dev_printer_devs );
        fb_hPrinterBuildList( &dev_printer_devs );

        /* Find printer attached to specified device */
        node = fb_hListDevFindDevice( &dev_printer_devs, lpt_proto->proto );
        if( node!=NULL ) {
            printer_name = strdup( node->printer_name );
        }

        fb_hListDevClear( &dev_printer_devs );
    }

    if( printer_name == NULL ) {
        result = fb_ErrorSetNum( FB_RTERROR_FILENOTFOUND );
    } else {
        if( *lpt_proto->emu!= '\0' ) {
            /* When EMULATION is used, we have to use the DC instead of
             * the PRINTER directly */
            hDc = CreateDCA( "WINSPOOL",
                             printer_name,
                             NULL,
                             NULL );
            fResult = hDc!=NULL;
        } else {
            /* User PRINTER directly */
            fResult = OpenPrinter(printer_name, &hPrinter, NULL);
        }
        if( !fResult ) {
            result = fb_ErrorSetNum( FB_RTERROR_FILENOTFOUND );
        }
    }

    if( lpt_proto->title && *lpt_proto->title ) {
			doc_title = strdup( lpt_proto->title );
		} else {
      doc_title = strdup( "FreeBASIC document" );
		}

    if( result==FB_RTERROR_OK ) {
        if( *lpt_proto->emu!= '\0' ) {
            int iJob;
            DOCINFO docInfo;
            memset( &docInfo, 0, sizeof(DOCINFO) );
            docInfo.cbSize = sizeof(DOCINFO);
            docInfo.lpszDocName = doc_title;
            iJob = StartDoc( hDc, &docInfo );
            if( iJob <= 0 ) {
                result = fb_ErrorSetNum( FB_RTERROR_FILEIO );
            } else {
                dwJob = (DWORD) iJob;
            }
        } else {
            DOC_INFO_1 DocInfo;
            DocInfo.pDocName = doc_title;
            DocInfo.pOutputFile = NULL;
            DocInfo.pDatatype = TEXT("RAW");

            dwJob = StartDocPrinter( hPrinter, 1, (BYTE*) &DocInfo );
            if( dwJob==0 ) {
                result = fb_ErrorSetNum( FB_RTERROR_FILEIO );
            }
        }
    }

    if( result==FB_RTERROR_OK ) {
        W32_PRINTER_INFO *pInfo = calloc( 1, sizeof(W32_PRINTER_INFO) );
        if( pInfo==NULL ) {
            result = fb_ErrorSetNum( FB_RTERROR_OUTOFMEM );
        } else {
            devInfo->driver_opaque = pInfo;
            pInfo->hPrinter = hPrinter;
            pInfo->dwJob = dwJob;
            pInfo->hDc = hDc;
            if( hDc!=NULL ) {
                LOGFONT lf;

                pInfo->Emu.dwFullSizeX = GetDeviceCaps( hDc, PHYSICALWIDTH );
                pInfo->Emu.dwFullSizeY = GetDeviceCaps( hDc, PHYSICALHEIGHT );
                pInfo->Emu.dwSizeX = GetDeviceCaps( hDc, HORZRES );
                pInfo->Emu.dwSizeY = GetDeviceCaps( hDc, VERTRES );
                pInfo->Emu.dwOffsetX = GetDeviceCaps( hDc, PHYSICALOFFSETX );
                pInfo->Emu.dwOffsetY = GetDeviceCaps( hDc, PHYSICALOFFSETY );
                pInfo->Emu.dwDPI_X = GetDeviceCaps( hDc, LOGPIXELSX );
                pInfo->Emu.dwDPI_Y = GetDeviceCaps( hDc, LOGPIXELSY );
#if 0
                pInfo->Emu.dwCurrentX = pInfo->Emu.dwOffsetX;
                pInfo->Emu.dwCurrentY = pInfo->Emu.dwOffsetY;
#else
                pInfo->Emu.dwCurrentX = 0;
                pInfo->Emu.dwCurrentY = 0;
#endif
                pInfo->Emu.clFore = RGB(0,0,0);
                pInfo->Emu.clBack = RGB(255,255,255);

                /* Start in 12 CPI monospace mode */
                EmuBuild_LOGFONT( &lf, pInfo, 12 );

                /* Should never fail - except when some default fonts were
                 * removed by hand (which is very unlikely) */
                pInfo->Emu.hFont = CreateFontIndirect( &lf );
                DBG_ASSERT( pInfo->Emu.hFont!=NULL );

                /* Register PRINT function */
                pInfo->Emu.pfnPrint = pFoundEmu->pfnPrint;

                /* Should not be necessary because this is the default */
                SetTextAlign( hDc, TA_TOP | TA_LEFT | TA_NOUPDATECP );

                EmuUpdateInfo( pInfo );
            }
        }
    }

    if( result!=FB_RTERROR_OK ) {
        if( dwJob!=0 ) {
            if( *lpt_proto->emu != '\0' ) {
                EndDoc( hDc );
            } else {
                EndDocPrinter( hPrinter );
            }
        }
        if( hPrinter!=NULL ) {
            ClosePrinter( hPrinter );
        }
        if( hDc!=NULL ) {
            DeleteDC( hDc );
        }
    }

    if( printer_name!=NULL )
        free( printer_name );
    if( doc_title!=NULL )
        free( doc_title );
		if( lpt_proto!=NULL )
			free(lpt_proto);

    return result;
}
/* parse argument list. we assume that all unrecognized arguments are file names. */
void CommandLineInfo::ParseCommandLine(const WCHAR *cmdLine)
{
    WStrVec argList;
    ParseCmdLine(cmdLine, argList);
    size_t argCount = argList.Count();

#define is_arg(txt) str::EqI(TEXT(txt), argument)
#define is_arg_with_param(txt) (is_arg(txt) && (argCount > n + 1))
#define additional_param() argList.At(n + 1)
#define has_additional_param() ((argCount > n + 1) && ('-' != additional_param()[0]))
#define handle_string_param(name) name.Set(str::Dup(argList.At(++n)))
#define handle_int_param(name) name = _wtoi(argList.At(++n))

    for (size_t n = 1; n < argCount; n++) {
        WCHAR *argument = argList.At(n);
        if (is_arg("-register-for-pdf")) {
            makeDefault = true;
            exitImmediately = true;
            return;
        }
        else if (is_arg("-silent")) {
            // silences errors happening during -print-to and -print-to-default
            silent = true;
        }
        else if (is_arg("-print-to-default")) {
            printerName.Set(GetDefaultPrinterName());
            if (!printerName)
                printDialog = true;
            exitWhenDone = true;
        }
        else if (is_arg_with_param("-print-to")) {
            handle_string_param(printerName);
            exitWhenDone = true;
        }
        else if (is_arg("-print-dialog")) {
            printDialog = true;
        }
        else if (is_arg_with_param("-print-settings")) {
            // argument is a comma separated list of page ranges and
            // advanced options [even|odd] and [noscale|shrink|fit]
            // e.g. -print-settings "1-3,5,10-8,odd,fit"
            handle_string_param(printSettings);
            str::RemoveChars(printSettings, L" ");
            str::TransChars(printSettings, L";", L",");
        }
        else if (is_arg("-exit-when-done") || is_arg("-exit-on-print")) {
            // only affects -print-dialog (-print-to and -print-to-default
            // always exit on print) and -stress-test (useful for profiling)
            exitWhenDone = true;
        }
        else if (is_arg_with_param("-inverse-search")) {
            str::ReplacePtr(&gGlobalPrefs->inverseSearchCmdLine, argList.At(++n));
            gGlobalPrefs->enableTeXEnhancements = true;
        }
        else if ((is_arg_with_param("-forward-search") ||
                  is_arg_with_param("-fwdsearch")) && argCount > n + 2) {
            // -forward-search is for consistency with -inverse-search
            // -fwdsearch is for consistency with -fwdsearch-*
            handle_string_param(forwardSearchOrigin);
            handle_int_param(forwardSearchLine);
        }
        else if (is_arg_with_param("-nameddest") || is_arg_with_param("-named-dest")) {
            // -nameddest is for backwards compat (was used pre-1.3)
            // -named-dest is for consistency
            handle_string_param(destName);
        }
        else if (is_arg_with_param("-page")) {
            handle_int_param(pageNumber);
        }
        else if (is_arg("-restrict")) {
            restrictedUse = true;
        }
        else if (is_arg("-invertcolors") || is_arg("-invert-colors")) {
            // -invertcolors is for backwards compat (was used pre-1.3)
            // -invert-colors is for consistency
            // -invert-colors used to be a shortcut for -set-color-range 0xFFFFFF 0x000000
            // now it non-permanently swaps textColor and backgroundColor
            gGlobalPrefs->fixedPageUI.invertColors = true;
        }
        else if (is_arg("-presentation")) {
            enterPresentation = true;
        }
        else if (is_arg("-fullscreen")) {
            enterFullScreen = true;
        }
        else if (is_arg_with_param("-view")) {
            ParseViewMode(&startView, argList.At(++n));
        }
        else if (is_arg_with_param("-zoom")) {
            ParseZoomValue(&startZoom, argList.At(++n));
        }
        else if (is_arg_with_param("-scroll")) {
            ParseScrollValue(&startScroll, argList.At(++n));
        }
        else if (is_arg("-console")) {
            showConsole = true;
        }
        else if (is_arg_with_param("-plugin")) {
            // -plugin [<URL>] <parent HWND>
            if (argCount > n + 2 && !str::IsDigit(*argList.At(n + 1)) && *argList.At(n + 2) != '-')
                handle_string_param(pluginURL);
            // the argument is a (numeric) window handle to
            // become the parent of a frameless SumatraPDF
            // (used e.g. for embedding it into a browser plugin)
            hwndPluginParent = (HWND)_wtol(argList.At(++n));
        }
        else if (is_arg_with_param("-stress-test")) {
            // -stress-test <file or dir path> [<file filter>] [<page/file range(s)>] [<cycle count>x]
            // e.g. -stress-test file.pdf 25x  for rendering file.pdf 25 times
            //      -stress-test file.pdf 1-3  render only pages 1, 2 and 3 of file.pdf
            //      -stress-test dir 301- 2x   render all files in dir twice, skipping first 300
            //      -stress-test dir *.pdf;*.xps  render all files in dir that are either PDF or XPS
            handle_string_param(stressTestPath);
            int num;
            if (has_additional_param() && str::FindChar(additional_param(), '*'))
                handle_string_param(stressTestFilter);
            if (has_additional_param() && IsValidPageRange(additional_param()))
                handle_string_param(stressTestRanges);
            if (has_additional_param() && str::Parse(additional_param(), L"%dx%$", &num) && num > 0) {
                stressTestCycles = num;
                n++;
            }
        }
        else if (is_arg_with_param("-n")) {
            handle_int_param(stressParallelCount);
        }
        else if (is_arg("-rand")) {
            stressRandomizeFiles = true;
        }
        else if (is_arg_with_param("-bench")) {
            WCHAR *s = str::Dup(argList.At(++n));
            pathsToBenchmark.Push(s);
            s = NULL;
            if (has_additional_param() && IsBenchPagesInfo(additional_param())) {
                s = str::Dup(argList.At(++n));
            }
            pathsToBenchmark.Push(s);
            exitImmediately = true;
        } else if (is_arg("-crash-on-open")) {
            // to make testing of crash reporting system in pre-release/release
            // builds possible
            crashOnOpen = true;
        }
        else if (is_arg("-reuse-instance")) {
            // for backwards compatibility, -reuse-instance reuses whatever
            // instance has registered as DDE server
            reuseDdeInstance = true;
        }
        // TODO: remove the following deprecated options within a release or two
        else if (is_arg("-esc-to-exit")) {
            gGlobalPrefs->escToExit = true;
        }
        else if (is_arg_with_param("-bgcolor") || is_arg_with_param("-bg-color")) {
            // -bgcolor is for backwards compat (was used pre-1.3)
            // -bg-color is for consistency
            ParseColor(&gGlobalPrefs->mainWindowBackground, argList.At(++n));
        }
        else if (is_arg_with_param("-lang")) {
            lang.Set(str::conv::ToAnsi(argList.At(++n)));
        }
        else if (is_arg("-set-color-range") && argCount > n + 2) {
            ParseColor(&gGlobalPrefs->fixedPageUI.textColor, argList.At(++n));
            ParseColor(&gGlobalPrefs->fixedPageUI.backgroundColor, argList.At(++n));
        }
        else if (is_arg_with_param("-fwdsearch-offset")) {
            handle_int_param(gGlobalPrefs->forwardSearch.highlightOffset);
            gGlobalPrefs->enableTeXEnhancements = true;
        }
        else if (is_arg_with_param("-fwdsearch-width")) {
            handle_int_param(gGlobalPrefs->forwardSearch.highlightWidth);
            gGlobalPrefs->enableTeXEnhancements = true;
        }
        else if (is_arg_with_param("-fwdsearch-color")) {
            ParseColor(&gGlobalPrefs->forwardSearch.highlightColor, argList.At(++n));
            gGlobalPrefs->enableTeXEnhancements = true;
        }
        else if (is_arg_with_param("-fwdsearch-permanent")) {
            handle_int_param(gGlobalPrefs->forwardSearch.highlightPermanent);
            gGlobalPrefs->enableTeXEnhancements = true;
        }
        else if (is_arg_with_param("-manga-mode")) {
            const WCHAR *s = argList.At(++n);
            gGlobalPrefs->comicBookUI.cbxMangaMode = str::EqI(L"true", s) || str::Eq(L"1", s);
        }
#if defined(SUPPORTS_AUTO_UPDATE) || defined(DEBUG)
        else if (is_arg_with_param("-autoupdate")) {
            n++; // this should have been handled already by AutoUpdateMain
        }
#endif
#ifdef DEBUG
        else if (is_arg("-enum-printers")) {
            EnumeratePrinters();
            /* this is for testing only, exit immediately */
            exitImmediately = true;
            return;
        }
#endif
        else {
            // Remember this argument as a filename to open
            WCHAR *filePath = NULL;
            if (str::EndsWithI(argList.At(n), L".lnk"))
                filePath = ResolveLnk(argList.At(n));
            if (!filePath)
                filePath = str::Dup(argList.At(n));
            fileNames.Push(filePath);
        }
    }
#undef is_arg
#undef is_arg_with_param
#undef additional_param
#undef has_additional_param
#undef handle_string_param
#undef handle_int_param
}
示例#6
0
bool PrintFile(BaseEngine *engine, WCHAR *printerName, bool displayErrors, const WCHAR *settings)
{
    bool ok = false;
    if (!HasPermission(Perm_PrinterAccess))
        return false;

#ifndef DISABLE_DOCUMENT_RESTRICTIONS
    if (engine && !engine->AllowsPrinting())
        engine = NULL;
#endif
    if (!engine) {
        if (displayErrors)
            MessageBoxWarning(NULL, _TR("Cannot print this file"), _TR("Printing problem."));
        return false;
    }

    ScopedMem<WCHAR> defaultPrinter;
    if (!printerName) {
        defaultPrinter.Set(GetDefaultPrinterName());
        printerName = defaultPrinter;
    }

    HANDLE printer;
    BOOL res = OpenPrinter(printerName, &printer, NULL);
    if (!res) {
        if (displayErrors)
            MessageBoxWarning(NULL, _TR("Printer with given name doesn't exist"), _TR("Printing problem."));
        return false;
    }

    LPDEVMODE devMode = NULL;
    // get printer driver information
    DWORD needed = 0;
    GetPrinter(printer, 2, NULL, 0, &needed);
    ScopedMem<PRINTER_INFO_2> infoData((PRINTER_INFO_2 *)AllocArray<BYTE>(needed));
    if (infoData)
        res = GetPrinter(printer, 2, (LPBYTE)infoData.Get(), needed, &needed);
    if (!res || !infoData || needed <= sizeof(PRINTER_INFO_2))
        goto Exit;

    LONG structSize = DocumentProperties(NULL,
        printer,
        printerName,
        NULL,                   /* Asking for size, so */
        NULL,                   /* not used. */
        0);                     /* Zero returns buffer size. */
    if (structSize < sizeof(DEVMODE)) {
        // If failure, inform the user, cleanup and return failure.
        if (displayErrors)
            MessageBoxWarning(NULL, _TR("Could not obtain Printer properties"), _TR("Printing problem."));
        goto Exit;
    }
    devMode = (LPDEVMODE)malloc(structSize);
    if (!devMode)
        goto Exit;

    // Get the default DevMode for the printer and modify it for your needs.
    LONG returnCode = DocumentProperties(NULL,
        printer,
        printerName,
        devMode,        /* The address of the buffer to fill. */
        NULL,           /* Not using the input buffer. */
        DM_OUT_BUFFER); /* Have the output buffer filled. */
    if (IDOK != returnCode) {
        // If failure, inform the user, cleanup and return failure.
        if (displayErrors)
            MessageBoxWarning(NULL, _TR("Could not obtain Printer properties"), _TR("Printing problem."));
        goto Exit;
    }

    ClosePrinter(printer);
    printer = NULL;

    {
        Print_Advanced_Data advanced;
        Vec<PRINTPAGERANGE> ranges;
        ApplyPrintSettings(settings, engine->PageCount(), ranges, advanced, devMode);

        PrintData pd(engine, infoData, devMode, ranges, advanced);
        ok = PrintToDevice(pd);
        if (!ok && displayErrors)
            MessageBoxWarning(NULL, _TR("Couldn't initialize printer"), _TR("Printing problem."));
    }

Exit:
    free(devMode);
    if (printer)
        ClosePrinter(printer);
    return ok;
}
/* parse argument list. we assume that all unrecognized arguments are file names. */
void CommandLineInfo::ParseCommandLine(const WCHAR* cmdLine) {
    WStrVec argList;
    ParseCmdLine(cmdLine, argList);
    size_t argCount = argList.size();

#define is_arg_with_param(_argNo) (param && _argNo == arg)
#define additional_param() argList.at(n + 1)
#define has_additional_param() ((argCount > n + 1) && ('-' != additional_param()[0]))
#define handle_string_param(name) name.SetCopy(argList.at(++n))
#define handle_int_param(name) name = _wtoi(argList.at(++n))

    for (size_t n = 1; n < argCount; n++) {
        WCHAR* argName = argList.at(n);
        int arg = GetArgNo(argName);
        WCHAR* param = nullptr;
        if (argCount > n + 1) {
            param = argList.at(n + 1);
        }
        if (RegisterForPdf == arg) {
            makeDefault = true;
            exitImmediately = true;
            return;
        } else if (Silent == arg) {
            // silences errors happening during -print-to and -print-to-default
            silent = true;
        } else if (PrintToDefault == arg) {
            printerName.Set(GetDefaultPrinterName());
            if (!printerName)
                printDialog = true;
            exitWhenDone = true;
        } else if (is_arg_with_param(PrintTo)) {
            handle_string_param(printerName);
            exitWhenDone = true;
        } else if (PrintDialog == arg) {
            printDialog = true;
        } else if (is_arg_with_param(PrintSettings)) {
            // argument is a comma separated list of page ranges and
            // advanced options [even|odd], [noscale|shrink|fit] and [autorotation|portrait|landscape]
            // e.g. -print-settings "1-3,5,10-8,odd,fit"
            handle_string_param(printSettings);
            str::RemoveChars(printSettings, L" ");
            str::TransChars(printSettings, L";", L",");
        } else if (ExitWhenDone == arg || ExitOnPrint == arg) {
            // only affects -print-dialog (-print-to and -print-to-default
            // always exit on print) and -stress-test (useful for profiling)
            exitWhenDone = true;
        } else if (is_arg_with_param(InverseSearch)) {
            inverseSearchCmdLine.SetCopy(argList.at(++n));
        } else if ((is_arg_with_param(ForwardSearch) || is_arg_with_param(FwdSearch)) && argCount > n + 2) {
            // -forward-search is for consistency with -inverse-search
            // -fwdsearch is for consistency with -fwdsearch-*
            handle_string_param(forwardSearchOrigin);
            handle_int_param(forwardSearchLine);
        } else if (is_arg_with_param(NamedDest) || is_arg_with_param(NamedDest2)) {
            // -nameddest is for backwards compat (was used pre-1.3)
            // -named-dest is for consistency
            handle_string_param(destName);
        } else if (is_arg_with_param(Page)) {
            handle_int_param(pageNumber);
        } else if (Restrict == arg) {
            restrictedUse = true;
        } else if (InvertColors1 == arg || InvertColors2 == arg) {
            // -invertcolors is for backwards compat (was used pre-1.3)
            // -invert-colors is for consistency
            // -invert-colors used to be a shortcut for -set-color-range 0xFFFFFF 0x000000
            // now it non-permanently swaps textColor and backgroundColor
            invertColors = true;
        } else if (Presentation == arg) {
            enterPresentation = true;
        } else if (Fullscreen == arg) {
            enterFullScreen = true;
        } else if (is_arg_with_param(View)) {
            ParseViewMode(&startView, param);
            ++n;
        } else if (is_arg_with_param(Zoom)) {
            ParseZoomValue(&startZoom, param);
            ++n;
        } else if (is_arg_with_param(Scroll)) {
            ParseScrollValue(&startScroll, param);
            ++n;
        } else if (Console == arg) {
            showConsole = true;
        } else if (is_arg_with_param(AppData)) {
            appdataDir.SetCopy(param);
            ++n;
        } else if (is_arg_with_param(Plugin)) {
            // -plugin [<URL>] <parent HWND>
            if (argCount > n + 2 && !str::IsDigit(*argList.at(n + 1)) && *argList.at(n + 2) != '-')
                handle_string_param(pluginURL);
            // the argument is a (numeric) window handle to
            // become the parent of a frameless SumatraPDF
            // (used e.g. for embedding it into a browser plugin)
            hwndPluginParent = (HWND)(INT_PTR)_wtol(argList.at(++n));
        } else if (is_arg_with_param(StressTest)) {
            // -stress-test <file or dir path> [<file filter>] [<page/file range(s)>] [<cycle
            // count>x]
            // e.g. -stress-test file.pdf 25x  for rendering file.pdf 25 times
            //      -stress-test file.pdf 1-3  render only pages 1, 2 and 3 of file.pdf
            //      -stress-test dir 301- 2x   render all files in dir twice, skipping first 300
            //      -stress-test dir *.pdf;*.xps  render all files in dir that are either PDF or XPS
            handle_string_param(stressTestPath);
            int num;
            if (has_additional_param() && str::FindChar(additional_param(), '*'))
                handle_string_param(stressTestFilter);
            if (has_additional_param() && IsValidPageRange(additional_param()))
                handle_string_param(stressTestRanges);
            if (has_additional_param() && str::Parse(additional_param(), L"%dx%$", &num) && num > 0) {
                stressTestCycles = num;
                n++;
            }
        } else if (is_arg_with_param(ArgN)) {
            handle_int_param(stressParallelCount);
        } else if (is_arg_with_param(Render)) {
            handle_int_param(pageNumber);
            testRenderPage = true;
        } else if (is_arg_with_param(ExtractText)) {
            handle_int_param(pageNumber);
            testExtractPage = true;
        } else if (Rand == arg) {
            stressRandomizeFiles = true;
        } else if (is_arg_with_param(Bench)) {
            WCHAR* s = str::Dup(param);
            ++n;
            pathsToBenchmark.Push(s);
            s = nullptr;
            if (has_additional_param() && IsBenchPagesInfo(additional_param())) {
                s = str::Dup(argList.at(++n));
            }
            pathsToBenchmark.Push(s);
            exitImmediately = true;
        } else if (CrashOnOpen == arg) {
            // to make testing of crash reporting system in pre-release/release
            // builds possible
            crashOnOpen = true;
        } else if (ReuseInstance == arg) {
            // for backwards compatibility, -reuse-instance reuses whatever
            // instance has registered as DDE server
            reuseDdeInstance = true;
        }
        // TODO: remove the following deprecated options within a release or two
        else if (is_arg_with_param(Lang)) {
            auto tmp = str::conv::ToAnsi(param);
            lang.Set(tmp.StealData());
            ++n;
        } else if (EscToExit == arg) {
            globalPrefArgs.Append(str::Dup(argList.at(n)));
        } else if (is_arg_with_param(BgColor) || is_arg_with_param(BgColor2) || is_arg_with_param(FwdSearchOffset) ||
                   is_arg_with_param(FwdSearchWidth) || is_arg_with_param(FwdSearchColor) ||
                   is_arg_with_param(FwdSearchPermanent) || is_arg_with_param(MangaMode)) {
            globalPrefArgs.Append(str::Dup(argList.at(n)));
            globalPrefArgs.Append(str::Dup(argList.at(++n)));
        } else if (SetColorRange == arg && argCount > n + 2) {
            globalPrefArgs.Append(str::Dup(argList.at(n)));
            globalPrefArgs.Append(str::Dup(argList.at(++n)));
            globalPrefArgs.Append(str::Dup(argList.at(++n)));
        }
#ifdef DEBUG
        else if (ArgEnumPrinters == arg) {
            EnumeratePrinters();
            /* this is for testing only, exit immediately */
            exitImmediately = true;
            return;
        }
#endif
        // this should have been handled already by AutoUpdateMain
        else if (is_arg_with_param(AutoUpdate)) {
            n++;
        } else {
            // Remember this argument as a filename to open
            WCHAR* filePath = nullptr;
            if (str::EndsWithI(argName, L".lnk"))
                filePath = ResolveLnk(argName);
            if (!filePath)
                filePath = str::Dup(argName);
            fileNames.Push(filePath);
        }
    }
#undef is_arg_with_param
#undef additional_param
#undef has_additional_param
#undef handle_string_param
#undef handle_int_param
}
/* parse argument list. we assume that all unrecognized arguments are file names. */
void CommandLineInfo::ParseCommandLine(WCHAR *cmdLine)
{
    WStrVec argList;
    ParseCmdLine(cmdLine, argList);
    size_t argCount = argList.Count();

#define is_arg(txt) str::EqI(TEXT(txt), argument)
#define is_arg_with_param(txt) (is_arg(txt) && param != NULL)
#define additional_param() argList.At(n + 1)
#define has_additional_param() ((argCount > n + 1) && ('-' != additional_param()[0]))

    for (size_t n = 1; n < argCount; n++) {
        WCHAR *argument = argList.At(n);
        WCHAR *param = NULL;
        if (argCount > n + 1)
            param = argList.At(n + 1);

        if (is_arg("-register-for-pdf")) {
            makeDefault = true;
            exitImmediately = true;
            return;
        }
        else if (is_arg("-silent")) {
            // silences errors happening during -print-to and -print-to-default
            silent = true;
        }
        else if (is_arg("-print-to-default")) {
            WCHAR *name = GetDefaultPrinterName();
            if (name) {
                str::ReplacePtr(&printerName, name);
                free(name);
            }
            exitWhenDone = true;
        }
        else if (is_arg_with_param("-print-to")) {
            str::ReplacePtr(&printerName, argList.At(++n));
            exitWhenDone = true;
        }
        else if (is_arg("-print-dialog")) {
            printDialog = true;
        }
        else if (is_arg_with_param("-print-settings")) {
            // argument is a comma separated list of page ranges and
            // advanced options [even|odd] and [noscale|shrink|fit]
            // e.g. -print-settings "1-3,5,10-8,odd,fit"
            str::ReplacePtr(&printSettings, argList.At(++n));
            str::RemoveChars(printSettings, L" ");
        }
        else if (is_arg("-exit-when-done") || is_arg("-exit-on-print")) {
            // only affects -print-dialog (-print-to and -print-to-default
            // always exit on print) and -stress-test (useful for profiling)
            exitWhenDone = true;
        }
        else if (is_arg_with_param("-bgcolor") || is_arg_with_param("-bg-color")) {
            // -bgcolor is for backwards compat (was used pre-1.3)
            // -bg-color is for consistency
            ParseColor(&bgColor, argList.At(++n));
        }
        else if (is_arg_with_param("-inverse-search")) {
            str::ReplacePtr(&inverseSearchCmdLine, argList.At(++n));
        }
        else if ((is_arg_with_param("-forward-search") ||
                  is_arg_with_param("-fwdsearch")) && argCount > n + 2) {
            // -forward-search is for consistency with -inverse-search
            // -fwdsearch is for consistency with -fwdsearch-*
            str::ReplacePtr(&forwardSearchOrigin, argList.At(++n));
            forwardSearchLine = _wtoi(argList.At(++n));
        }
        else if (is_arg_with_param("-fwdsearch-offset")) {
            fwdSearch.offset = _wtoi(argList.At(++n));
        }
        else if (is_arg_with_param("-fwdsearch-width")) {
            fwdSearch.width = _wtoi(argList.At(++n));
        }
        else if (is_arg_with_param("-fwdsearch-color")) {
            ParseColor(&fwdSearch.color, argList.At(++n));
        }
        else if (is_arg_with_param("-fwdsearch-permanent")) {
            fwdSearch.permanent = _wtoi(argList.At(++n));
        }
        else if (is_arg("-esc-to-exit")) {
            escToExit = true;
        }
        else if (is_arg("-reuse-instance")) {
            // find the window handle of a running instance of SumatraPDF
            // TODO: there should be a mutex here to reduce possibility of
            // race condition and having more than one copy launch because
            // FindWindow() in one process is called before a window is created
            // in another process
            reuseInstance = (FindWindow(FRAME_CLASS_NAME, 0) != NULL);
        }
        else if (is_arg_with_param("-lang")) {
            free(lang);
            lang = str::conv::ToAnsi(argList.At(++n));
        }
        else if (is_arg_with_param("-nameddest") || is_arg_with_param("-named-dest")) {
            // -nameddest is for backwards compat (was used pre-1.3)
            // -named-dest is for consistency
            str::ReplacePtr(&destName, argList.At(++n));
        }
        else if (is_arg_with_param("-page")) {
            pageNumber = _wtoi(argList.At(++n));
        }
        else if (is_arg("-restrict")) {
            restrictedUse = true;
        }
        // TODO: remove -invert-colors and -set-color-range in favor
        //       of the UI settable gGlobalPrefs.useSysColors(?)
        else if (is_arg("-invertcolors") || is_arg("-invert-colors")) {
            // -invertcolors is for backwards compat (was used pre-1.3)
            // -invert-colors is for consistency
            // -invert-colors is a shortcut for -set-color-range 0xFFFFFF 0x000000
            // (i.e. it sets white as foreground color and black as background color)
            colorRange[0] = WIN_COL_WHITE;
            colorRange[1] = WIN_COL_BLACK;
        }
        else if (is_arg("-set-color-range") && argCount > n + 2) {
            STATIC_ASSERT(sizeof(colorRange[0]) == sizeof(int), colorref_as_int);
            ParseColor((int *)&colorRange[0], argList.At(++n));
            ParseColor((int *)&colorRange[1], argList.At(++n));
        }
        else if (is_arg("-presentation")) {
            enterPresentation = true;
        }
        else if (is_arg("-fullscreen")) {
            enterFullscreen = true;
        }
        else if (is_arg_with_param("-view")) {
            ParseViewMode(&startView, argList.At(++n));
        }
        else if (is_arg_with_param("-zoom")) {
            ParseZoomValue(&startZoom, argList.At(++n));
        }
        else if (is_arg_with_param("-scroll")) {
            ParseScrollValue(&startScroll, argList.At(++n));
        }
        else if (is_arg("-console")) {
            showConsole = true;
        }
        else if (is_arg_with_param("-plugin")) {
            // -plugin [<URL>] <parent HWND>
            if (!str::IsDigit(*param) && has_additional_param())
                str::ReplacePtr(&pluginURL, argList.At(++n));
            // the argument is a (numeric) window handle to
            // become the parent of a frameless SumatraPDF
            // (used e.g. for embedding it into a browser plugin)
            hwndPluginParent = (HWND)_wtol(argList.At(++n));
        }
        else if (is_arg_with_param("-stress-test")) {
            // -stress-test <file or dir path> [<file filter>] [<page/file range(s)>] [<cycle count>x]
            // e.g. -stress-test file.pdf 25x  for rendering file.pdf 25 times
            //      -stress-test file.pdf 1-3  render only pages 1, 2 and 3 of file.pdf
            //      -stress-test dir 301- 2x   render all files in dir twice, skipping first 300
            //      -stress-test dir *.pdf;*.xps  render all files in dir that are either PDF or XPS
            str::ReplacePtr(&stressTestPath, argList.At(++n));
            int num;
            if (has_additional_param() && str::FindChar(additional_param(), '*')) {
                str::ReplacePtr(&stressTestFilter, additional_param());
                n++;
            }
            if (has_additional_param() && IsValidPageRange(additional_param())) {
                str::ReplacePtr(&stressTestRanges, additional_param());
                n++;
            }
            if (has_additional_param() && str::Parse(additional_param(), L"%dx%$", &num) && num > 0) {
                stressTestCycles = num;
                n++;
            }
        }
        else if (is_arg_with_param("-n")) {
            stressParallelCount = _wtoi(argList.At(++n));
        }
        else if (is_arg("-rand")) {
            stressRandomizeFiles = true;
        }
        else if (is_arg_with_param("-bench")) {
            WCHAR *s = str::Dup(argList.At(++n));
            pathsToBenchmark.Push(s);
            s = NULL;
            if (has_additional_param() && IsBenchPagesInfo(additional_param())) {
                s = str::Dup(additional_param());
                n++;
            }
            pathsToBenchmark.Push(s);
            exitImmediately = true;
        } else if (is_arg("-crash-on-open")) {
            // to make testing of crash reporting system in pre-release/release
            // builds possible
            crashOnOpen = true;
        } else if (is_arg_with_param("-manga-mode")) {
            // TODO: we should have a ui for this instead of remembering it globally
            // in prefs
            WCHAR *s = argList.At(++n);
            cbxR2L = str::EqI(L"true", s) || str::Eq(L"1", s);
        }
#if defined(SUPPORTS_AUTO_UPDATE) || defined(DEBUG)
        else if (is_arg_with_param("-autoupdate")) {
            n++; // this should have been handled already by AutoUpdateMain
        }
#endif
#ifdef DEBUG
        else if (is_arg("-enum-printers")) {
            EnumeratePrinters();
            /* this is for testing only, exit immediately */
            exitImmediately = true;
            return;
        }
#endif
        else {
            // Remember this argument as a filename to open
            WCHAR *filePath = NULL;
            if (str::EndsWithI(argList.At(n), L".lnk"))
                filePath = ResolveLnk(argList.At(n));
            if (!filePath)
                filePath = str::Dup(argList.At(n));
            fileNames.Push(filePath);
        }
    }
#undef is_arg
#undef is_arg_with_param
#undef additional_param
#undef has_additional_param
}