Ignore:
Timestamp:
Sep 29, 2010, 5:09:55 PM (15 years ago)
Author:
dmik
Message:

Added argcA and argvA (valid only after WinMain() is entered) that may be used by applications to access ANSI versions of command line arguments w/o performing manual command line conversion and parsing. The standard argc and argv arguments, as opposed, are always in the OEM codepage.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kernel32/wprocess.cpp

    r21463 r21464  
    5050#include "initterm.h"
    5151#include "directory.h"
     52#include "shellapi.h"
    5253
    5354#include <win\ntddk.h>
     
    8586PCSTR   pszCmdLineA;                    /* ASCII/ANSII commandline. */
    8687PCWSTR  pszCmdLineW;                    /* Unicode commandline. */
     88char    **__argvA = NULL;               /* command line arguments in ANSI */
     89int     __argcA = 0;                    /* number of arguments in __argcA */
    8790
    8891//Process database
     
    13621365
    13631366
     1367/*************************************************************************
     1368 * CommandLineToArgvW (re-exported as [SHELL32.7])
     1369 */
     1370/*************************************************************************
     1371*
     1372* We must interpret the quotes in the command line to rebuild the argv
     1373* array correctly:
     1374* - arguments are separated by spaces or tabs
     1375* - quotes serve as optional argument delimiters
     1376*   '"a b"'   -> 'a b'
     1377* - escaped quotes must be converted back to '"'
     1378*   '\"'      -> '"'
     1379* - an odd number of '\'s followed by '"' correspond to half that number
     1380*   of '\' followed by a '"' (extension of the above)
     1381*   '\\\"'    -> '\"'
     1382*   '\\\\\"'  -> '\\"'
     1383* - an even number of '\'s followed by a '"' correspond to half that number
     1384*   of '\', plus a regular quote serving as an argument delimiter (which
     1385*   means it does not appear in the result)
     1386*   'a\\"b c"'   -> 'a\b c'
     1387*   'a\\\\"b c"' -> 'a\\b c'
     1388* - '\' that are not followed by a '"' are copied literally
     1389*   'a\b'     -> 'a\b'
     1390*   'a\\b'    -> 'a\\b'
     1391*
     1392* Note:
     1393* '\t' == 0x0009
     1394* ' '  == 0x0020
     1395* '"'  == 0x0022
     1396* '\\' == 0x005c
     1397*/
     1398LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
     1399{
     1400  DWORD argc;
     1401  HGLOBAL hargv;
     1402  LPWSTR  *argv;
     1403  LPCWSTR cs;
     1404  LPWSTR arg,s,d;
     1405  LPWSTR cmdline;
     1406  int in_quotes,bcount;
     1407
     1408  if (*lpCmdline==0) {
     1409  /* Return the path to the executable */
     1410    DWORD size;
     1411
     1412    hargv=0;
     1413    size=16;
     1414    do {
     1415      size*=2;
     1416      hargv=GlobalReAlloc(hargv, size, 0);
     1417      argv=(LPWSTR*)GlobalLock(hargv);
     1418    } while (GetModuleFileNameW((HMODULE)0, (LPWSTR)(argv+1), size-sizeof(LPWSTR)) == 0);
     1419    argv[0]=(LPWSTR)(argv+1);
     1420    if (numargs)
     1421      *numargs=2;
     1422
     1423    return argv;
     1424  }
     1425
     1426  /* to get a writeable copy */
     1427  argc=0;
     1428  bcount=0;
     1429  in_quotes=0;
     1430  cs=lpCmdline;
     1431  while (1) {
     1432    if (*cs==0 || ((*cs==0x0009 || *cs==0x0020) && !in_quotes)) {
     1433    /* space */
     1434      argc++;
     1435      /* skip the remaining spaces */
     1436      while (*cs==0x0009 || *cs==0x0020) {
     1437        cs++;
     1438      }
     1439      if (*cs==0)
     1440        break;
     1441      bcount=0;
     1442      continue;
     1443    } else if (*cs==0x005c) {
     1444    /* '\', count them */
     1445      bcount++;
     1446    } else if ((*cs==0x0022) && ((bcount & 1)==0)) {
     1447    /* unescaped '"' */
     1448      in_quotes=!in_quotes;
     1449      bcount=0;
     1450    } else {
     1451    /* a regular character */
     1452      bcount=0;
     1453    }
     1454    cs++;
     1455  }
     1456  /* Allocate in a single lump, the string array, and the strings that go with it.
     1457  * This way the caller can make a single GlobalFree call to free both, as per MSDN.
     1458    */
     1459    hargv=GlobalAlloc(0, argc*sizeof(LPWSTR)+(strlenW(lpCmdline)+1)*sizeof(WCHAR));
     1460  argv=(LPWSTR*)GlobalLock(hargv);
     1461  if (!argv)
     1462    return NULL;
     1463  cmdline=(LPWSTR)(argv+argc);
     1464  strcpyW(cmdline, lpCmdline);
     1465
     1466  argc=0;
     1467  bcount=0;
     1468  in_quotes=0;
     1469  arg=d=s=cmdline;
     1470  while (*s) {
     1471    if ((*s==0x0009 || *s==0x0020) && !in_quotes) {
     1472    /* Close the argument and copy it */
     1473      *d=0;
     1474      argv[argc++]=arg;
     1475
     1476      /* skip the remaining spaces */
     1477      do {
     1478        s++;
     1479      } while (*s==0x0009 || *s==0x0020);
     1480
     1481      /* Start with a new argument */
     1482      arg=d=s;
     1483      bcount=0;
     1484    } else if (*s==0x005c) {
     1485    /* '\\' */
     1486      *d++=*s++;
     1487      bcount++;
     1488    } else if (*s==0x0022) {
     1489    /* '"' */
     1490      if ((bcount & 1)==0) {
     1491      /* Preceeded by an even number of '\', this is half that
     1492        * number of '\', plus a quote which we erase.
     1493          */
     1494          d-=bcount/2;
     1495        in_quotes=!in_quotes;
     1496        s++;
     1497      } else {
     1498      /* Preceeded by an odd number of '\', this is half that
     1499        * number of '\' followed by a '"'
     1500          */
     1501          d=d-bcount/2-1;
     1502        *d++='"';
     1503        s++;
     1504      }
     1505      bcount=0;
     1506    } else {
     1507    /* a regular character */
     1508      *d++=*s++;
     1509      bcount=0;
     1510    }
     1511  }
     1512  if (*arg) {
     1513    *d='\0';
     1514    argv[argc++]=arg;
     1515  }
     1516  if (numargs)
     1517    *numargs=argc;
     1518
     1519  return argv;
     1520}
     1521
    13641522/**
    13651523 * Internal function which gets the commandline (string) used to start the current process.
     
    13831541    APIRET  rc;                         /* OS/2 return code. */
    13841542    BOOL    fQuotes;                    /* Flag used to remember if the exe filename should be in quotes. */
     1543    LPWSTR *argvW;
     1544    int     i;
     1545    ULONG   cb;
    13851546
    13861547    /** @sketch
     
    15281689            WideCharToMultiByte(CP_ACP, 0, pszCmdLineW, -1, (LPSTR)pszCmdLineA, cch-1, 0, NULL);
    15291690            ((LPSTR)pszCmdLineA)[cch-1] = 0;
     1691
     1692            // now, initialize __argcA and __argvA. These global variables are for the convenience
     1693            // of applications that want to access the ANSI version of command line arguments w/o
     1694            // using the lpCommandLine parameter of WinMain and parsing it manually
     1695            LPWSTR *argvW = CommandLineToArgvW(pszCmdLineW, &__argcA);
     1696            if (argvW != NULL)
     1697            {
     1698                // Allocate space for both the argument array and the arguments
     1699                // Note: intentional memory leak, pszCmdLineW will not be freed
     1700                // or allocated after process startup
     1701                cb = sizeof(char*) * __argcA + cch + __argcA;
     1702                __argvA = (char **)malloc(cb);
     1703                if (__argvA != NULL)
     1704                {
     1705                    psz = ((char *)__argvA) + sizeof(char*) * __argcA;
     1706                    cb -= sizeof(char*) * __argcA;
     1707                    for (i = 0; i < __argcA; ++i)
     1708                    {
     1709                        cch = WideCharToMultiByte(CP_ACP, 0, argvW[i], -1, psz, cb, 0, NULL);
     1710                        if (!cch)
     1711                        {
     1712                            DebugInt3();
     1713                            dprintf(("KERNEL32: InitCommandLine(%p): WideCharToMultiByte() failed\n", pszPeExe));
     1714                            rc = ERROR_NOT_ENOUGH_MEMORY;
     1715                            break;
     1716                        }
     1717                        psz[cch++] = '\0';
     1718                        __argvA[i] = psz;
     1719                        psz += cch;
     1720                        cb -= cch;
     1721                    }
     1722                }
     1723                else
     1724                {
     1725                    DebugInt3();
     1726                    dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed (3)\n", pszPeExe, cch));
     1727                    rc = ERROR_NOT_ENOUGH_MEMORY;
     1728                }
     1729            }
     1730            else
     1731            {
     1732                DebugInt3();
     1733                dprintf(("KERNEL32: InitCommandLine(%p): CommandLineToArgvW() failed\n", pszPeExe));
     1734                rc = ERROR_NOT_ENOUGH_MEMORY;
     1735            }
    15301736        }
    15311737        else
    15321738        {
    15331739            DebugInt3();
    1534             dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed (2)\n", pszPeExe, cch));
     1740            dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed (2)\n", pszPeExe, cch * 2));
    15351741            rc = ERROR_NOT_ENOUGH_MEMORY;
    15361742        }
     
    19792185    FREE_OEM(lpCommandLine)
    19802186    FREE_OEM(lpApplicationName)
     2187
     2188    #undef FREE_OEM
     2189    #undef ALLOC_OEM
    19812190
    19822191    return rc;
Note: See TracChangeset for help on using the changeset viewer.