ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

C言語とC++言語コミュのエディットコントロールの16進数表示について教えてください。

  • mixiチェック
  • このエントリーをはてなブックマークに追加
初めまして。Mixiでコミュニティに参加するのは初めてなので参加を迷ったんですが、C言語の質問をさせてもらえるということで参加させていただきます。
さっそく質問なのですが、WindowsでMIDIファイルの数値を読み込んで16進数で表示するプログラムを作っています。

WinApi、VisualC++ 2008です。

int MidiOpen (void)
{
/*コモンダイアログの情報*/
OPENFILENAME ofn;

/*メモリの確保のための変数*/
HANDLE hFile; //ファイルハンドル
HGLOBAL hMem; //動的メモリの確保先
DWORD fileSize = 0; //ファイルのサイズ
DWORD dwAccByte;
char *data;

/*構造体のメンバをセット*/
memset (&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof (OPENFILENAME);
ofn.hwndOwner = hMain;
ofn.lpstrFilter = "mid(*.mid)\0\0";
ofn.lpstrFile = szFilePath;
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFile = MAX_PATH;
ofn.nMaxFileTitle = MAX_PATH;
ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = "mid";
ofn.lpstrTitle = "ファイルを開く";

/*ダイアログを開いてパス、ファイル名を格納*/
/*失敗した場合はメッセージボックスを表示*/
if (GetOpenFileName (&ofn) == 0){
MessageBox (hMain, "ファイルのオープンに失敗しました。", "エラー", MB_OK);
return -1;
}

/*メモリの操作を行うためにファイルハンドルを取得する*/
hFile = CreateFile (szFilePath, GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

/*ファイルハンドルが示すファイルのサイズを取得*/
fileSize = GetFileSize (hFile, NULL);

/*サイズに応じてメモリを確保*/
hMem =GlobalAlloc (GHND, sizeof(char) *fileSize);
if (hMem == NULL){
MessageBox (hMain, "メモリの確保に失敗しました", "エラー", MB_OK);
return -1;
}

/*確保したメモリの場所をセット*/
data = (char*)GlobalLock (hMem);

/*確保したメモリにファイルの中身をコピー*/
ReadFile (hFile, data, fileSize, &dwAccByte, NULL);

/*エディタ部に内容を表示*/
Edit_SetText (hEdit, data);

/*ファイルのクローズとメモリの開放*/
CloseHandle (hFile);
GlobalUnlock (hMem);
GlobalFree (hMem);

return 0;
}

ウィンドウプロシージャからこの関数を呼び出します。
エディットコントロールに表示するためにEdit_SetTextを使っていますが、それは私がこれしか知らなかったからです。
この状態だと読み込んだファイルの先頭の"MThd"しか表示されません。
どのようにすれば16進数を表示できますか?
0x00 0x00のように半角スペースを空けて表示したいです。

知識すくなくてすいません;;

ちなみにMIDIファイルの数値って1バイトずつ扱うようなイメージがあるのですが、VC++だと1バイトの型はcharですよね?char使っていて間違いないでしょうか?

コメント(10)

1バイトの読み取りはcharでいいですが、Windowsプログラミング的にはcharのtypedefでByteとかあった気がします。
16進数の表示は、データ長を元に適切なサイズのバッファを用意して、sprintf等で16進数 <-> 文字列変換すればいいんじゃないでしょうか。
>うづきさん
当日のうちに書き込みしてくださったのにお返事が遅くなってすみません。ありがとうございます。

なるほど、byteがありましたね!聞いたことはありましたが今まで使ったことがなかったので忘れていました;;

sprintfで、というのは新しいchar型のバッファを用意するとして、

char *dataCopy;
GLOBAL cpyMem;
//省略
cpyMem = GlobalAlloc (GHND, sizeof(char) *fileSize);
dataCopy = (char*)GlobalLock (cpyMem);

sprintf (dataCopy, "%x", data);
Edit_SetText (hEdit, DataCopy);
.......

のような感じでしょうか?
実行してみると数字がいくつかだけ表示されただけで、ファイル内のデータすべては出力されなかったようなのですが、sprintfの使い方が間違っているのでしょうか?こちらもあまり使ったことがないもので……
なにが間違っているのかご指摘いただけるとありがたいです。
Edit_SetText()は、「現在の内容」を丸ごと書き換えるはずです。
予め設定する文字列を全て入れたものでEdit_SetText()するか、
Edit_SetSel()で最終位置を選択してEdit_ReplaceSel()で追加することになるかと。

ReadFile()で読み込んだデータのサイズは判明していますので、
sprintf()で変換するときのサイズも算出可能なハズです。
"0x%02x "であれば、読み込んだサイズ*5+1になりますな。
Edit_SetSel()とEdit_ReplaceSel()で置き換えていくならそんなに大きいサイズは必要ありませんが。
# いちいち追記していくことになりますから全てのデータを設定し終わるまでそこそこの時間が必要になるでしょう。

VisualC++ 2008ってコトなので、UNICODEかMBCSかで注意は必要…ですかね。
>cckさん
なるほど、\0ですね。私が見たEdit_SetTextの例題が!= EOFしか使っていなかったので、ヌル文字のことは考えたことがありませんでした。参考になります。

sprintfはfor文で使うべきだったのですね……てっきり配列ごと指定してよいのかと思っていました。ありがとうございます。

>瀬戸っぷさん
つまり、何も指定しないで2度目のEdit_SetTextを使用すると前に出力した内容の上から書き換えられてしまうということですね。肝に銘じておきます。
Edit_SetSelやEditReplaseSelは経験が無く、使いこなす自信が無いので、とりあえずは先に全ての文字列を入れてしまう方法でいきたいとおもいます。
でも使えるようにしておくと便利そうですね。いろいろ教えていただいてありがとうございます。


お陰さまで
for (i = 0; i <= fileSize, i ++)
sprintf (dataCopy[i * 2]; "%X", data[i]);

とするときちんとファイルの中身を表示することができました!
皆さんありがとうございます!
質問とは関係ないけど。

/*構造体のメンバをセット*/
memset (&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);

こう書いておけばofnの型が変わっても安心だよね。
>cckさん
そうですね。00が0となってしまうので、02Xでそろえたほうが見やすくなりました。ありがとうございます。

>花抹茶さん
確かに、私が初めてOPENFILENAMEを使ったときに読んだ本にもそう書いてあったのに、そうするのを忘れていました;;
そのほうが安心ですよね……わざわざありがとうございます!

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

C言語とC++言語 更新情報

C言語とC++言語のメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング