Windows程式內如何取得Command line參數?

可以使用GetCommandLine()來取得Command line參數,下面一個簡易範例。

  int argc;
  char** argv = CommandLineToArgv(GetCommandLine(), argc);

  string img_path = argc>1?argv[1]:" ";

  delete[] argv[0]; // 使用完要刪除
  delete[] argv; // 使用完要刪除


因為微軟的SDK只有提供寬字元版的CommandLineToArgvW,所以我花了點時間寫一般字元的版本,這個處理並不包含參數中間內有雙引號的情況,不過參數的頭尾是雙引號有做,所以某些參數可能跟系統的不太一樣。

我使用的是狀態機的作法,因為這樣比較容易發想與處理,用一張圖就可以搞定想法與實作。
第一次掃描將空白符號與不必要的符號都設為'\0',並獲得參數數目 argc。
第二次掃描將資料設定到argv中,因為第一次掃描已經將不必要的符號都設為'\0'所以可以用簡便的方法處理argv

char** CommandLineToArgv(char* sys_cmd, int& argc)
{
  int  curr_state;
  char **argv, **argv_itr;
  char *cmd_itr, *loc;
  int   cmd_len = strlen(sys_cmd);
  char *cmd     = new char[cmd_len+1];
  char *cmd_end = cmd+cmd_len;
  
  strncpy(cmd, sys_cmd, cmd_len);
  cmd[cmd_len] = '\0';
  
  argc = 0;
  curr_state = 0;
  for (cmd_itr=cmd ; cmd_itr!=cmd_end ; ++cmd_itr)
  {
    switch(curr_state)
    {
      case 0:
        if (isspace(*cmd_itr))
          *cmd_itr = '\0';
        else
        {
          if (*cmd_itr=='"')
          {
            *cmd_itr = '\0';
            curr_state = 2;
          }
          else
            curr_state = 1;

          argc++;
        }
      break;

      case 1: // character
        if (isspace(*cmd_itr))
        {
          *cmd_itr = '\0';
          curr_state = 0;
        }
      break;

      case 2: // quater
        if (*cmd_itr =='"')
        {
          *cmd_itr = '\0';
          loc = cmd_itr;
          curr_state = 3;
        }
      break;

      case 3:
        if (isspace(*cmd_itr))
        {
          *cmd_itr = '\0';
          curr_state = 0;          
        }
        else 
        {
          *loc = *cmd_itr; // move character
          *cmd_itr = '\0';
        }
      break;

    }// end switch
  }

  argv = new char*[argc];

  // find the first non-zero char location, and move the data to the head 
  for (cmd_itr=cmd ; !*cmd_itr && cmd_itr!=cmd_end ; ++cmd_itr)
    ; // empty
  memmove(cmd, cmd_itr, cmd_len+1-(cmd_itr-cmd));

  curr_state = 0;
  argv_itr = argv;
  for (cmd_itr=cmd ; cmd_itr!=cmd_end ; ++cmd_itr)
  {
    switch(curr_state)
    {
      case 0:
        if (*cmd_itr)
        {
          *argv_itr++ = cmd_itr;
          curr_state = 1;
        }
      break;

      case 1:
        if (*cmd_itr == '\0')
          curr_state = 0;
      break;
    }
  }

  return argv;
}

留言