C言語関係掲示板

過去ログ

No.156.ストリングテーブルから文字列を取得し、ファイルとして保存したい


No.995

リソースとして取り込んだファイルをHD上に保存する方法
投稿者---Ras(2002/02/01 20:20:47)


初めまして。C言語初心者のRasって言います♪
VisualC++でリソースとして取り込んだテキストファイルをHDに保存したいのですが、どう〜してもやり方がわかりません(苦笑)
というかリソースにアクセスする方法すらわかりません(苦笑)
どなたか教えていただけると嬉しいです♪

No.1000

Re:リソースとして取り込んだファイルをHD上に保存する方法
投稿者---B.Smith(2002/02/02 15:18:36)


こんにちは。

「VisualC++でリソースとして取り込んだテキストファイル…」というのは、ストリングテーブルの事を言っていますか?
Visual C++、リソースへのアクセス、という所から「ストリングテーブルから文字列を取得し、ファイルとして保存したい」と解釈しますけど、もし、違っていたら、現在の状況をもうちょっと詳しく教えてください(単純なCで作成しているのか、MFCを使っているか、等も含めて)。

(ストリングテーブルへのアクセスを行う場合)
Windowsのプログラムは、API、MFCを問わず、普通のC/C++よりも少し難しくなってしまうのですが、時間をかけてじっくりとやってみてください。

Windows APIに関数LoadStringというのがあります。この関数はリソース内のストリングテーブルから指定の文字列を取得します。
    int LoadString(HINSTANCE hInstance,UINT wResourceID,
                   LPTSTR lpBuffer,int nBufferSize);

hInstanceはリソースを持っているモジュールのインスタンスハンドル、wResourceIDは対象のリソースID、lpBufferは取得した文字列を格納するバッファ、nBufferSizeはlpBufferのサイズを表します。戻り値には、取得した文字列の長さ(末尾ヌルを含まない)を返し、エラーの場合はゼロを返します。

インスタンスハンドルですが、WinMainからスタートしている場合は、WinMainの1番目の引数がそうです。MFCを使用している場合はAfxGetApp()->m_hInstance、コンソールアプリケーションの場合は関数GetModuleHandleの戻り値をセットしてください。

例えば、ストリングテーブルからIDS_STRING1の文字列を取得したい場合、以下のように表現します。
#include <windows.h>

#define  MAX_STRING     256
     ・
     ・
    int     nLength;
    char    Buf[MAX_STRING+1];

    nLength = LoadString(hInstance,IDS_STRING1,Buf,MAX_STRING);

文字列を取得できれば、後はファイルへ出力するだけです。
以下の例は、グローバル配列ResIDで指定した文字列を改行文字付きでファイルへ出力する処理です。
例.
#include <windows.h>

#define MAX_STRING      256 /* 最大文字列長 */

UINT    ResID[] = {
(リソースID),…
};

BOOL    SaveStringTable(HINSTANCE hInstance,LPSTR FileName)
{
    HANDLE  hFile;
    DWORD   dwWrite;
    int     nIdx,nLength;
    char    szBuf[MAX_STRING+1+1];/* 改行+末尾ヌル */

    hFile = CreateFile(     /* ファイルのオープン */
            FileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        return FALSE;

    /* リソースID分繰り返す */
    for(nIdx = 0;nIdx < sizeof(ResID ) / sizeof(int );nIdx++){
        /* 文字列の取得 */
        if (!(nLength = LoadString(hInstance,ResID[nIdx],szBuf,MAX_STRING)))
            continue;

        *(szBuf + nLength) = '\n';/* 改行文字の追加 */
        nLength++;
        *(szBuf + nLength) = 0;   /* 末尾ヌルを追加 */

        /* ファイルへの書き込み */
        if (WriteFile(hFile,szBuf,nLength,&dwWrite,NULL) == FALSE ||
            (DWORD )nLength > dwWrite){
            CloseHandle(hFile);
            return FALSE;
        }
    }

    CloseHandle(hFile);     /* ファイルのクローズ */
    return TRUE;
}


No.1014

StringTableのサイズを取得する方法
投稿者---Ras(2002/02/04 18:59:01)


B.Smithさんありがとうございました!!
すいません、確かに説明不足でしたね。
・・で、でも僕は初心者すぎて何を説明すればいいのかさっぱりで(苦笑)
実際StringTableってのも知りませんでした(笑)
リソースでインポートすればいいのかな?ってずっと思ってたもんで。
ご迷惑をおかけしました(笑)

で、教えてもらった関数なのですが・・・。
確かに使えます。文字も取得できました。
が、どうしても文字列の「先頭」から指定した文字数しか取得出来ません。
ま、まぁそういう関数なんだから仕方無いと言われればしょうがないんですが(苦笑)
今までファイル操作は全部 
FILE *fp;
みたいにポインタでやってたんで、読み込んだら次読み込むときはその続きからって感じだったんですよ。
B.Smithさんが作ってくれた関数ですと、最初に文字列を256文字ずつに分けてStringTableに保存するってゆう方法なんでしょうか?
僕の場合、このStringTableに保存する量が結構不定期なので先頭から最後まで一気に読み込みたいんです。
だったら大きいサイズの配列を作ればいいのでは?
とお思いでしょうが・・・貧乏性のせいか、メモリを極力使いたくないんですよね(苦笑)
StringTableのサイズが分かれば、new,deleteで領域確保、保存、領域解放
してすっきり出来るんですが。
StringTableのサイズ取得の関数教えていただければ嬉しいことこの上ないです。
ちなみにsizeof()してみたら当然の事ながら4が返ってきました(苦笑)

No.1015

なんてこってす(泣)
投稿者---Ras(2002/02/04 19:20:17)


StringTable、1000バイトしか取り込めないみたいですね(苦笑)
う、う〜ん、10KBぐらいあるファイルを一気に取り込んで、
一気に保存する方法ないですかね(苦笑)
今スクリーンセーバーを作ってるので、EXE単体にして外部のファイルを読み込ませないようにしたいんです。
どうかよろしくお願いします・・・。

No.1017

Re:なんてこってす(泣)
投稿者---B.Smith(2002/02/04 22:47:39)


>StringTable、1000バイトしか取り込めないみたいですね(苦笑)

多分2048バイトくらいまでだと思います。

>う、う〜ん、10KBぐらいあるファイルを一気に取り込んで、
>一気に保存する方法ないですかね(苦笑)
>今スクリーンセーバーを作ってるので、EXE単体にして外部のファイルを読み込ませないようにしたいんです。

最も簡単な方法は、リソースとしてではなく、グローバル領域にすべてのテキストデータを置いてしまうことです。一つの文字列としては10kバイトは大きすぎるので、各行毎に変数を割り当てる等の工夫が必要になりますが、リソースよりは扱いが容易になると思います。
リソースにしたい場合は、各行単位にIDを割り振るという形になると思います。

(リソースサイズの取得について)
リソース全体のサイズを1回の処理で取得することは、リソース(今回の場合は文字列)が1つしか無い場合以外はできないと思います。
単体のリソース(ID毎のリソース)のサイズならば求められますので、余分なメモリを確保したくないのであれば、これを応用してみてください。

単体のリソースのサイズを取得するには、

関数FindResourceによりリソースハンドルを取得
関数SizeofResourceによりサイズを取得

この手順で出来ます。
    HRSRC       hRes;
    DWORD       dwSize;

    /* リソースハンドルの取得 */
    hRes = FindResource(hInstance,MAKEINTRESOURCE(IDS_STRING1),RT_STRING);
    if (!hRes)
        return FALSE;

    /* リソースサイズの取得 */
    dwSize = SizeofResource(hInstance,hRes);

関数FindResourceでリソースハンドルを取得します。引数は左から、インスタンスハンドル、リソースID、リソースの種類です。
リソースIDはマクロMAKEINTRESOURCEを使用してください。リソースの種類は、ストリングテーブルの場合はRT_STRINGを指定します。

dwSizeに文字列のサイズ(単体のリソースのサイズ)が格納されますので、それを使ってメモリを確保することができます。dwSizeで返される値は、アライメントの影響を受けて正確な値にはならない場合があります(実際よりも大きくなる)。


No.1026

ありがとうございました。解決しました♪
投稿者---Ras(2002/02/05 17:43:03)


色々検討してみた結果こういうふうになりました
HGLOBAL hGlobal;
hGlobal = LoadResource ( hInstance, FindResource ( hInstance, MAKEINTRESOURCE ( IDR_TEXT1 ), "TEXT" ) );
char *lpszText = ( char * ) LockResource ( hGlobal );
>>ファイル書き込み
FreeResource ( hGlobal );

テキストファイルをカスタムリソースとして取り込み、リソースをロックし直接ファイルに書き込む方向になりました。
速度面とか心配でしたが、全然平気でした♪
B.Smithさん本当に色々ありがとうございました♪
おかげで作成が順調に進みそうです。


戻る


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