アプリ版:「スタンプのみでお礼する」機能のリリースについて

Visual C++で、
unsigned char*型の変数を、一旦ファイルに保存しておいて、
後にそれを読み込んで使用する、ということをしたいのですが、
GetPrivateProfileStringとWritePrivateProfileStringを利用しようと考えました。

具体的にはPC-OP-RS1という製品を使った、
テレビのリモコンプログラムなんですが、
このデバイスの操作APIが、
赤外線信号をunsigned char*型で受け取ります。
これをファイルに記述しておいて、
好きなときに呼び出したいのですが、
前述の2つの関数は、
渡せる方がLPCTSTR型となっていますが、これがよくわかりません。
どうすれば実現できるでしょうか?
別の方法を取ったほうがいいでしょうか?

A 回答 (6件)

今回は最初「文字列かな」と思って書いたところから始まったのであれですが



「数個程度のデータ」が詰まったバイナリのfileout, fileinを扱うとハッキリ分かっているなら
実際には私だったらfopen_s,fwrite,fcloseあたりで手軽に済ませる可能性が高いです。


これを応用していけば市販アプリでよくあるような「独自の巨大なファイル形式」の作成もできます。
巨大なファイルになる場合は、私は読み取り時は少なくとも「メモリマップドファイル」をお勧めします。ファイルシークは時間ががかりますので。
参考

・ファイルをメモリのように「メモリマップドファイルクラス」
http://marupeke296.com/DXCLS_MemoryMappedFile.html


その場合はどっかにファイルの構成(仕様)が分かるような仕様書をメモしておくと後々楽です。(経験談)


めちゃめちゃ本格的なことを追求していえば
コンストラクタが絡むと「例外安全」という問題が若干無視できなくなるのと
(現状ではstd::ofstreamやstd::istreamの仕様に依存することになる)

char*にキャストしているのが「美しくない」という印象もあるので

まぁその辺を自分でラッパークラス作っちゃって、内部で何使ってようが、書き変えたくなったら呼び出し側はノータッチで後で簡単に変えられるように出来るのがC++の本当の良さですが。


「WritePrivateProfileString」という題名で
独自バイナリファイルの入出力の話が出てるとは
普通は考えにくいでしょうから(「教えてgoo」を今後見る人のためにも)

「独自のバイナリ形式のファイル入出力の方法」とか何とかの名前つけて
別途質問を立ててそっちで
「とりあえずこんな感じでやってみたのですが、これこれこうなってうまくいきません」
とか
「一応出来てることはできていますが、もっといい方法はありますでしょうか?」

などの形跡などを書きつつ質問をしていただければ
その時時間があれば、私も答えてみましょう。
    • good
    • 0
この回答へのお礼

何から何まで面倒みていただいてありがとうございました。

そうですね、
今回の初めの質問内容から逸脱しすぎました。
他の方の少しでも参考になるように、
この辺りでやめておきます。

また機会があればよろしくお願いします。

お礼日時:2012/02/18 20:17

大抵のライブラリって


outだったらinがあり
writeだったreadがあるものです。
なので、とりあえずおんなじよ~にかいて見てください

unsigned char *data2;
data2 = (unsigned char*)malloc(240);
std::ifstream ifs("binary.dat",std::ios::binary);
ifs >> data2;

のとこを

unsigned char *data2;
data2 = (unsigned char*)malloc(240);
std::ifstream ifs("binary.dat",std::ios::binary);
ifs.read( (char*)data2, 240 );


一応、省略されてるだけだろうとは思いますが
mallocで確保した場合は、データを使い終わってから
freeで解放することを忘れないでください。

free( data2 );
//その後data2ポインタを使いまわす場合はdata2 = NULL;としておくのが推奨

この場合はたった240バイト固定、ということで
環境にもよりますが、大抵は

unsigned char data2[240];

とローカル変数にしてしまっても全然OKと思いますが

以上の内容を踏まえてまだ出来ない場合は教えてください。

この回答への補足

何度も詳しくありがとうございます。
ほんとに助かります。

無事取り出すことが出来るようになりました。
ついで、というとあれですが、
もうひとつ質問させていただいてもよろしいでしょうか?

実は、
このようなバイナリ列を、
複数(5つくらい)プログラム内で書き込み、読み込みする必要があるのですが、
一つのファイルに5つ書きこんで、順番に読み込むにはどうしたらいいでしょうか?
具体的には5つの変数を用意して、
それぞれに対応したバイナリーデータをファイルから読み込んで格納する、
といったことをしたいです。

補足日時:2012/02/18 14:22
    • good
    • 0

>unsigned char *signal;


>Receive(signal);  //APIの関数
>printf("%s\n",signal);
>としてみたら文字化けしました。

当たり前ですが、受信する前にsignalは有効な領域指しているんですよね?
普通ならこういう場合、ポインタと一緒に領域のサイズも渡すんですが…
今回は「240バイト固定」のバッファが指定されているのでサイズ情報の引き渡しはないのでしょう。

で……文字列じゃなくてバイト列…ですよね?
No.2さんのリンク先見ると。
バイト列ならprintf()での表示は無理でしょう。

その他、細かいことは既に回答されているので……。
# もちろん、私ならこういう場合はふつ~にバイナリデータとして扱いますけどね。
# ファイルに落とした後でならバイナリエディタで眺めることもできますし。
    • good
    • 0

おおっと、最初「文字列かな?」


と思って書いたstd::ofstreamのまま修正してませんでしたね

unsigned char buff[240];
//データ受け取り
std::ofstream of("test.dat", std::ios::binary);
of.write((char*)buff, 240 );

正しくはこんな感じかな。

この回答への補足

皆様回答ありがとうございます。

早速以下のようにプログラムをかきなおしてみました。

unsigned char *data;
data = (unsigned char*)malloc(240);
//dataに受信データを書き込む
std::ofstream of("binary.dat",std::ios::binary);
of.write((char*)data,240);
of.close();

unsigned char *data2;
data2 = (unsigned char*)malloc(240);
std::ifstream ifs("binary.dat",std::ios::binary);
ifs >> data2;
//data2を送信

しかしこれだと正しい信号が送信できていないようです。
ちなみに、当たり前ですが、data2ではなくdataを送信すると正常に動作します。
どうしたらいいでしょうか。

補足日時:2012/02/17 15:29
    • good
    • 0

それってこんな感じのバイナリ列じゃないですか?


http://netakiri.net/labo/ctrl_remote_station_sam …

データ列の詳しいフォーマットの情報はまだ発見していませんが
単一の文字列とは思えません。


無理やり文字列にキャストして…というのも不可能ではないですが
この場合は240Bytesのバイナリをそのまま書きだしてしまった方が、ずっとコード的に分かりやすいと思います。


fopen_s → fwrite → fclose

あるいは
CreateFile → WriteFile → CloseHandle

あるいはC++を使えるのなら

#include <fstream>

std::ofstream ofs( "ファイル名.txt" );
ofs << データ << std::endl;


あるいはメモリマップドファイル
などなど、方法は多岐にわたります。


なお、LPCTSTRやGetPrivateProfileStringなどの詳細について
しっかり把握したい場合は、今後のためにもこちらを読んでおくことをお勧めします。

・_T("")マクロだのL""マクロだのLPCTSTRだのの世界一詳しい解説
http://victreal.com/Junk/_T/index.html


プロジェクトのプロパティ→構成プロパティ→全般→文字セット
のところが「Unicode 文字セットを使用する」

の場合、
_T("abc")はL"abc"に置き換えられ(const wchar_t*)

「マルチ バイト文字セットを使用する」
の場合は
_T("abc")は"abc"に置き換えられます(const char*)


また、必要部分だけ抜粋すると
LPCTSTRはwinNT.hでこのようになっているはずです。

#ifdef UNICODE
typedef LPCWSTR PCTSTR, LPCTSTR;
#else
typedef LPCSTR PCTSTR, LPCTSTR, PCUTSTR, LPCUTSTR;
#endif

「Unicode 文字セットを使用する」の場合は上のLPCWSTRと等価になります

「マルチ バイト文字セットを使用する」の場合は下のLPCSTRと等価になります

LPCWSTRはconst WCHAR*
LPCSTRはconst CHAR*

と等価になり

また
WritePrivateProfileStringはwinbaseで

#ifdef UNICODE
#define WritePrivateProfileString WritePrivateProfileStringW
#else
#define WritePrivateProfileString WritePrivateProfileStringA
#endif

となっています。

WritePrivateProfileStringWの引数はLPCWSTR
WritePrivateProfileStringAの引数はLPCSTR

となっていますね。
    • good
    • 0

>Visual C++で、



バージョンはなんですか?
あるいは、使用している文字セットは?
「マルチ バイト文字セットを使用する」か「Unicode 文字セットを使用する」か……

>このデバイスの操作APIが、
>赤外線信号をunsigned char*型で受け取ります。

「文字列」として受け取れるのですか?
「バイト列」だった場合は、そのままではiniファイルには書き込み出来ませんが。

>渡せる方がLPCTSTR型となっていますが、これがよくわかりません。

入っているのが文字列で文字セットが適切であればキャストして渡すような感じになります。
デバイスから受け取るのがunsigned char*であれば…文字セットは「マルチバイト」の方になるかと思いますけど。
バイト列なら先に書いた通り無理です。
# バイト列を16進文字列で文字とすれば可能でしょう。変換の手間(とコスト)が掛かりますが。

バイト列ならfwrite/fread(あるいはWriteFile/ReadFileなどのAPI)で読み書きとした方が楽…でしょうね。
# 人間が見たい場合は面倒でしょうけど。

この回答への補足

2010で「マルチ バイト文字セットを使用する」になっています。
http://1c3.world.coocan.jp/wiki/index.php?%A5%B3 …
こちらのページで公開されているAPIを使っているのですが、
試しに
unsigned char *signal;
Receive(signal);  //APIの関数
printf("%s\n",signal);
としてみたら文字化けしました。
これってバイト列を受信しているからなんでしょうか?

補足日時:2012/02/16 18:00
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!