質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.22%

win32apiのGetCommandLine()でコマンドライン引数がうけとれない

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 7,573

geitsu

score 14

発生している問題・エラーメッセージ

win32apiのGetCommandLine()でコマンドライン引数をうけとると

"C:Users\ユーザー名\documents\visual studio
2015\Projects\Win32Project3\Debug\Win32Project3.exe"
\Users\ユーザー名\Desktop\test.txt

とコマンドライン引数だけでなく実行ファイルのパスも受け取ってしまって
下記のソースコードのCreateFile()が失敗します
GetComanndLine()を使わない方法でもいいのでコマンドライン引数をうけとってCreateFile()を実行する方法を教えてください

コマンドライン引数はソリューションエクスプローラー>プロパティ>デバッグ>コマンド引数から設定しました

該当のソースコード

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR lpCmdLine,int nCmdShow) 
{
    HANDLE hFile;

    hFile = CreateFile(GetCommandLine(), GENERIC_READ, 0, NULL,CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) 
    {
        MessageBox(NULL, GetCommandLine(),TEXT("エラー"), MB_OK);
        return 1;
    }

    CloseHandle(hFile);

    return 0;
}

試したこと

WinMainのlpCmdLine引数はPSTRからLPCWSTRへの型変換ができないのでCreateFile()の引数にできなかったです
CommandLinetoArgvW()はLPWSTRからLPCWSTRの型変換ができないのでCreateFile()の引数にできなかったです

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

__argv__argcというグローバル変数が定義されているのでそれを使う(正規の方法ではない)

EternalWindows

CommandLineToArgvWで受け取った文字列をWideCharToMultiByteで変換してから渡す。

Win32アプリのコマンドライン引数を解析するラッパー関数を書く

ANSI版からUnicode対応に置き換える
Visual Studioでプロジェクトを作ったらデフォルトでこの設定のはず。

WinMain → wWinMain
CreateFile → CreateFileW


追記:

CommandLineToArgvWの使い方を知りたいみたいだったので追記。
Unicode対応だとわかりやすいようにWが付いた方のAPIを指定してます。

#include <windows.h>

int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR lpCmdLine, int)
{
    int Argc;        // コマンドライン引数の個数
    LPWSTR *Argv;    // コマンドライン引数のリスト
    HANDLE hFile = nullptr;

    // GetCommandLine()を使用した場合は、Argv[0]に実行時のパスが入り、
    // Argv[1]以降にコマンドライン引数が入る
    // lpCmdLineを指定した場合は、Argv[0]に1番目のコマンドライン引数が入る
    Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
    // Argv = CommandLineToArgvW(lpCmdLine, &Argc);

    hFile = CreateFileW(Argv[1], GENERIC_READ, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
    if (hFile == INVALID_HANDLE_VALUE) {
        MessageBoxW(nullptr, L"ファイルのオープンに失敗しました", L"エラー", MB_OK);
        return 1;
    }

    CloseHandle(hFile);

    return 0;
}

これで>test.exe text1.txt text2.txt text3.txtのような感じで、スペースで区切って複数のオプションを指定した場合、

Argv[0]にtest.exe
Argv[1]にtext1.txt
Argv[2]にtext2.txt ... というようにコマンドライン引数が格納され、

CreateFileにArgv[1]を指定しているので、text1.txtが作成され他は無視されるというわけです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/05 19:55

    WinMainをwWinMainに変えたらlpCmdLine引数をCreateFile()の引数にできました
    ありがとうございました

    キャンセル

  • 2017/05/05 20:29

    何を参考にしているかはわかりませんが、
    Unicode対応で書くとなると

    TCHARとかLPCTSTR、LPTSTRって何???
    http://www.usefullcode.net/2006/11/tcharlpctstrlptstr.html

    紛らわしいぞ!LPCTSTR、LPTSTR、LPSTR、LPCSTRは全部意味が違う!
    http://www.usefullcode.net/2006/11/lpctstrlptstrlpstrlpcstr.html

    あたりを読んでマルチバイト文字とワイド文字の違いは理解したほうが良いと思います。
    古いサンプルはマルチバイト文字が前提になっていると思うので。

    キャンセル

  • 2017/05/05 22:11 編集

    ありがとうございます
    理解できました

    キャンセル

+1

GetCommandLine() が実行ファイル名を含むのは仕様です。

WinMain

lpCmdLine
アプリケーションのコマンドラインが格納された NULL で終わる文字列へのポインタが入ります。プログラム名は含まれません。コマンドライン全体を取り出すには、GetCommandLine 関数を使ってください。

ANSI アプリケーションは、WinMain 関数の lpCmdLine パラメータによりコマンドライン文字列にアクセスすることができます。ただし、この文字列にはプログラム名は含まれません。WinMain 関数が Unicode 文字列を返せないのは、lpCmdLine パラメータがデータ型として LPTSTR ではなく LPSTR を使っているためです。GetCommandLineW 関数を使えば Unicode のコマンドライン文字列を取得できます。

GetCommandLine で取得し、CommandLineToArgvW を使って解析してください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/05 19:55

    CommandLinetoArgvW()はLPWSTRからLPCWSTRの型変換ができないのでCreateFile()の引数にできなかったです

    キャンセル

  • 2017/05/05 19:58

    他の方法で解決されたので蛇足になりますが、



    まあいいや。

    キャンセル

  • 2017/05/05 22:11

    教えて

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る