C言語関係掲示板

過去ログ

No.137.Windows XP でエスケープシーケンスが使えない


No.877

Windows XP 上でのコンソールアプリケーションでのエスケープシーケンス
投稿者---rash(2002/01/18 22:54:07)


はじめまして、rash というものです。

最近 Windows XP を導入して困ったことが発覚しました。
Visual C++ 6.0 SP5 を使用して、コンソールアプリケーション(DOS画面上で実行されるやつ)のプログラムを作成していると座標指定や、文字色を変えたり、画面をクリアしたり、カーソルを消したりする制御文字(エスケープシーケンス)が使用できないことが分かって、困ってしまいました。
エスケープシーケンス以外を使用して、何とかできないでしょうか?

よろしくお願いします。


サンプルソース:

#include        <stdio.h>

#define         locate(x, y)    printf("\x1b[%d;%dH", x, y)     //座標指定
#define         cls()           printf("\x1b[2J")               //画面クリア
#define         color(c)        printf("\x1b[%dm", c)           //文字色変更
#define         cur_off()       printf("\x1b[>5h")              //カーソル消去

void main(void)
{
        printf("テストテスト〜\n画面クリアされてますか?\n\n");
        cls();

        locate(10, 10); color(31);
        printf("赤くて座標(10, 10)・・・のはず\n\n");
        color(37);

        cur_off();
        printf("カーソル消したかな?\n");

        getchar();
}



No.879

Re:Windows XP 上でのコンソールアプリケーションでのエスケープシーケンス
投稿者---B.Smith(2002/01/18 23:54:14)


XPは良く分からないのですが、NT系(2000含む)と同じような現象なので、NTでの解決方法をご紹介します。関連した問題ならば、参考になるかもしれません。

NT系は、デフォルトではコンソールウインドウでエスケープシーケンスは使えません。これは、コンソール起動時にANSI.SYSが入らないためです。
WINNTフォルダ(またはWindowsフォルダ、OSがインストールされている所)の中のSYSTEM32フォルダ内に"CONFIG.NT"というファイルが存在します。その中に以下の1行を追加してください。
        device=%SystemRoot%\system32\ANSI.SYS

友達、学校、職場や客先のマシン等、環境を簡単に変えてはならない場合もあります。その場合の代替関数をご紹介します。Windows APIを直接制御します。この方法はすべてのWindows(Win32)で適用できます。
プログラム開始時に関数InitializeStdioを一度だけ実行し、文字列を表示したい場合は関数ShowString、一文字入力を行いたい場合は関数GetChar、画面をクリアしたい場合は関数ClearScreenを実行してください(一文字入力の処理は、APIでの標準入出力のサンプルとして入れてあります)。
この関数は、すでにお分かりの通り、MS-DOS上では実行できません。
#include <windows.h>

static HANDLE   hStdin = (HANDLE )-1L;
static HANDLE   hStdout = (HANDLE )-1L;

/* APIによる標準入出力の初期化 */
void    InitializeStdio(void )
{
    /* 新たにコンソールウインドウを作成する     */
    /* 起動時のコンソールを対象としたい場合は   */
    /* 以下の行を無効にしてください             */
    FreeConsole();  AllocConsole();

    hStdin = GetStdHandle(STD_INPUT_HANDLE);    /* 標準入力ハンドルの取得 */
    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);  /* 標準出力ハンドルの取得 */
}

/* 文字列の表示 */
void    ShowString(
            char    *pString, /* 表示文字列 */
            int     xPos,     /* X座標 */
            int     yPos)     /* Y座標 */
{
    DWORD   result;
    COORD   coord;

    /* 標準出力ハンドルが取得できていない場合は中断 */
    if (hStdout == (HANDLE )-1L)
        return;

    /* 表示位置の設定 */
    coord.X = xPos;coord.Y = yPos;
    SetConsoleCursorPosition(hStdout,coord);

    /* 文字列の表示 */
    WriteConsole(hStdout,pString,strlen(pString ),&result,NULL);
}

/* 一文字入力…戻り値に押されたキーのコードが返る */
int     GetChar(void )
{
    DWORD   dwSaveState;
    DWORD   dwRead;
    BYTE    Key;

    /* 標準入力ハンドルが取得できていない場合は中断 */
    if (hStdin == (HANDLE )-1L)
        return;

    /* 現行コンソールモードの退避と再設定 */
    GetConsoleMode(hStdin,&dwSaveState);
    SetConsoleMode(hStdin,0L);

    /* 1文字読み込み */
    ReadFile(hStdin,&Key,1L,&dwRead,NULL);

    /* コンソールモードの復元 */
    SetConsoleMode(hStdin,dwSaveState);

    return Key;
}

/* コンソールのクリア */
void    ClearScreen(void )
{
    static COORD                coordScreen;
    DWORD                       dwCharsWritten;
    DWORD                       dwConsoleSize;
    CONSOLE_SCREEN_BUFFER_INFO  csbi;

    /* 標準出力ハンドルが取得できていない場合は中断 */
    if (hStdout == (HANDLE )-1L)
        return;

    /* コンソールのキャラクタバッファ情報を取得 */
    if (GetConsoleScreenBufferInfo(hStdout,&csbi) == FALSE)
        return;

    /* キャラクタバッファサイズを計算 */
    dwConsoleSize = csbi.dwSize.X * csbi.dwSize.Y;

    /* キャラクタバッファを空白で埋める */
    FillConsoleOutputCharacter(
        hStdout,' ',dwConsoleSize,coordScreen,&dwCharsWritten);

    /* 現在のテキスト属性の取得 */
    if (GetConsoleScreenBufferInfo(hStdout,&csbi) == FALSE)
        return;

    /* すべての文字に対して取得したテキスト属性を適用する */
    FillConsoleOutputAttribute(
        hStdout,csbi.wAttributes,dwConsoleSize,coordScreen,&dwCharsWritten);

    /* カーソル位置を左上角に移動 */
    SetConsoleCursorPosition(hStdout,coordScreen);
}


No.881

Re:Windows XP 上でのコンソールアプリケーションでのエスケープシーケンス
投稿者---B.Smith(2002/01/19 00:07:51)


すいません。代替関数についての追加です。

・表示する文字列の色を変更したい場合は、関数WriteConsoleを行う前に関数SetConsoleTextAttributeにより色(文字属性)を変更します。
	SetConsoleTextAttribute(hStdout,FOREGROUND_BLUE | BACKGROUND_GREEN);

この例では、文字を青、背景を緑にします。
色の種類については、ヘルプを参照してください。

・コンソールアプリケーションの場合は、USER32.LIBをリンクしてください。



No.880

Re:Windows XP 上でのコンソールアプリケーションでのエスケープシーケンス
投稿者---ともじ(2002/01/18 23:59:08)


rashさん、こんばんは。

>最近 Windows XP を導入して困ったことが発覚しました。
>(エスケープシーケンス)が使用できないことが分かって、困ってしまいました。

専門学校ではNTを使っていますが、NTも標準ではエスケープシーケンス
が使えませんでした。
WINNT\SYSTEM32\CONFIG.NTにANSI.SYSを次のように指定してやると
使えるようになりました。
"device=%SystemRoot%\system32\ANSI.SYS"

XPも同様の処理で使えるようになるのではないでしょうか。


No.883

解決せず・・・
投稿者---rash(2002/01/19 01:05:42)


CONFIG.NT を操作する方法を試してみましたが、何も変化は見られませんでした。
(内部的なことで何か変化は起こっているかもしれませんが、まったく各章はありません)

ごめんなさい。B.Smith さんの代わりの方法はまだ初心でまったくさっぱりです。(^^;

No.884

Re:解決せず・・・
投稿者---rash(2002/01/19 01:09:27)


すみません、追記です。

>CONFIG.NT を操作する方法を試してみましたが〜・・・

もちろん操作後、再起動をかけました。

No.893

Re:解決せず・・・
投稿者---ともじ(2002/01/19 23:46:34)


>CONFIG.NT を操作する方法を試してみましたが、何も変化は見られませんでした。

検索で調べてAnsi.sysのパスを直接指定しても駄目ですか?

No.894

Re:解決せず・・・
投稿者---2児のオヤジ です(2002/01/20 21:05:13)


動かない原因は、config.ntがシステムファイルになってないためと思います。

この辺はやったことがないので、調査中です。



No.922

Re:解決せず・・・
投稿者---rash(2002/01/23 22:38:27)


>検索で調べてAnsi.sysのパスを直接指定しても駄目ですか?

フルパス(device=C:\WINDOWS\system32\ANSI.SYS)ってことですか?
それでも駄目でした。

No.925

Re:解決せず・・・
投稿者---2児のオヤジ です。(2002/01/24 22:07:31)


>フルパス(device=C:\WINDOWS\system32\ANSI.SYS)ってことですか?
>それでも駄目でした。

私のPCでは、2000の環境でもダメです。

config.ntが不明ファイルになってるのが気に入らないんですが、
調べてもよくわからないです。

検索で載っているのは、config.ntに追加するってことだけで、
それ以前の問題については載ってないですね。

たぶん、XPでも、2000でも同じ問題でつまずいてるのだと思います。


No.927

Re:解決せず・・・
投稿者---B.Smith(2002/01/25 16:12:36)


ごめんなさい。質問の意味がようやく分かりました。

コンソールは、16ビットのアプリケーションに対してのみ、MS-DOSエミュレーションが有効になります。Visual C++ 6.0で作成したアプリケーションは32ビットなので、コンソールアプリケーションでコンパイルしても、エスケープシーケンスは使えないことになります。

16ビットコンパイラを用意できるのであれば、エスケープシーケンスを使用することができます。また、ビデオBIOSを直接制御する、ということも可能です。
Visual C++ 6.0でコンパイルする場合は、エスケープシーケンスを使用することをあきらめなければなりません(Win APIを使用しなければなりません)。



No.936

Re:解決せず・・・
投稿者---2児のオヤジ です。(2002/01/25 19:32:11)



>コンソールは、16ビットのアプリケーションに対してのみ、MS-DOSエミュレーションが有効になります。Visual C++ 6.0で作成したアプリケーションは32ビットなので、コンソールアプリケーションでコンパイルしても、エスケープシーケンスは使えないことになります。

言われている意味はわかります。 でも、疑問が1つWIN98に、コンパイルしたプログラムを持っていくと、ちゃんと作動します。

config.ntがうまく初期化してくれてない感じです。
但、おっしゃる通り32ビットでデバックしてるみたいですが、
どうも???わかりません。

No.946

Re:解決せず・・・
投稿者---B.Smith(2002/01/26 15:38:07)


(一度投稿したのですが、内容が変だったので訂正しました)
ここで言うNTは2000を含みます。XPに関しては良く分かりませんが、共通点を見出せれば問題解決の足がかりになるかもしれません。

NTでは、16ビットアプリケーションが起動する時、以下のファイルが自動的に実行されます。
・MS-DOSアプリケーションの場合、Config.nt、Autoexec.nt
・Windowsアプリケーションの場合、Config.wow、Autoexec.nt

32ビットアプリケーションの場合は実行されません。16ビットアプリケーションをコンソール上で起動すると、一回だけ画面がクリアされ、設定が読み込まれたような内容を表示すると思います。これが、上記のファイルです。Visual C++ 6.0で作成したアプリケーションは32ビットなので、このファイルは読み込まれません。
これらのことから、NT上では16ビットアプリケーションのみ、ANSI.SYSを使用できることになります。ちなみに、これらのファイルの検索パスは、レジストリ内の以下の場所に保存されています。
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment

確かなことは言えませんが、16ビット処理を残しているWin 9xではエスケープシーケンスが使用できるかもしれません。

実行環境は、人によりさまざまですので、違いが発生しても不思議ではありません。そういう意味からも、私としては、プログラム上ですべてを解決することを推奨します。ソースコードの移植性を取るよりも、「どこの環境でも通用する実行ファイル」の方が、使用者としては良いはずです(ここで言う環境とはWindowsを表します)。

表示用の処理を用意することは、決して難しいことではありません。ソースコードに移植性を保たせたければ、例えば以下のようにマクロ定義してしまうのも一つの手です。
(関数ShowString、関数ClearScreenはNo.879のサンプルを使用しているとします)
#ifdef      UNDER_NT
#define     SHOWSTRING(A,B,C)       ShowString(A,B,C)
#define     CLS                     ClearScreen()

#else
#define     SHOWSTRING(A,B,C)       printf("\033[%d;%dH%s",C,B,A)
#define     CLS                     printf("\033[2J")

#endif

一番良いのは、OSのバージョンにより、呼び出す関数を切り替えることですが、まあ、表示関数程度であるならば、そこまですることも無いと思います。

Visual C++ 6.0でコンソールアプリケーションを作成する場合には、No.879のサンプルソースをそのまま使えます。ソースをファイルにしたらプロジェクトに取り込み、コンパイルするだけです(コマンドプロンプトからコンパイルする場合はUSER32.LIBをリンクしてください)。
実は、このサンプル、関数GetChar内に一箇所問題がありますが、すぐに分かる問題点なので、使用する際は修正してください(実に簡単なミスです)。

16ビットコンパイラを使用する場合は、別途質問してください。



No.949

Re:解決せず・・・
投稿者---2児のオヤジ です。(2002/01/26 18:24:25)


>実行環境は、人によりさまざまですので

確かにそうですね

>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager

このあたりの Memory Management とか、特にさわりたいところですし。

>私としては、プログラム上ですべてを解決することを推奨します。

そんな感じがします。大変良い勉強になりました。ありがとうございます。

戻る


「初心者のためのポイント学習C言語」 Last modified:2002.02.03
Copyright(c) 2000-2002 TOMOJI All Rights Reserved