鏑矢の憂鬱2000年12月後半
透明1ドットイメージ
 
2000/12/16 (Sat)
・今日は久しぶりにほめかぶ作り。結構めんどいなー(汗)。あんまいい例じゃないけど、行き当たりばったりでどんどん組んでいって、今は最初のユーザーインターフェイスまわり。ベースは ATL/WTL で、使い方とか調べながら組んでいってます。
 
・アプリの雰囲気は、旧 VB 風っつーか、マック風っつーか、一番上にタイトルバーとメニューとツールバー、あとモードレスダイアログ4つって感じになります。今日は、そのダイアログを、ツールバーのボタンで表示/非表示にする部分を組んでました。ツールバーってコモンコントロールみたいなもんなんですね、そーゆーのも知らなかった(汗)。そういうアプリって作ったことないんですよ。フリーウェアはウィンドウすらなかったりするし。
 
・簡単に書いとくと、ツールバーのボタンを「押しっぱなし」にするためには TB_CHECKBUTTON をツールバーのウィンドウに送ればOK。ちなみに WTL に CToolBarCtrl っつークラスがあるんでこれを利用すると楽。ツールバーのウィンドウハンドルの取得は、 WTL で SDI プロジェクト作ったら CMainFrame::OnCreate() で CreateSimpleToolBarCtrl() を呼び出している所があるからその戻り値を使えばOK。
 
・ ATL/WTL は、ウィンドウハンドルとかがなんか直アクセスしたりすることが多いんで、その辺が複雑。その辺を解析しながら使っていく感じになりそうだなー。どっちかってゆーと、実際にプログラム組むよりも、ライブラリの解析の方が楽しいかもしんない(爆)。
 
・でわまたっ!
透明1ドットイメージ
 
2000/12/17 (Sun)
・今日もほめぱげ作り。ダイアログを「サイズ可変」にしたんだけど、ボタンとか自動的に移動したりしないんですね(汗)。てっきりそういうの全自動だと思ってた。 WM_SIZE でひとつひとつ移動したりサイズ変更したりするのかー、ちょっとめんどそうだなー。
 
・あと、レジストリまわりのテスト。 ATL に CRegKey っていうクラスがあるんでどんな感じに使えるのか調べてました。基本は API と同じ。引数を省略できる分、使いやすいかな。でも CWinApp::WriteProfileInt() みたいな便利なのはないっぽいです。あと、普通に書き込むよりも、メンバ変数と結び付ける形とかにしたいし。
 
・もうそろそろ、 ATL/WTL 用ライブラリを作ってこうかなぁと思ってます。サポート用関数とか用意していかないと少し辛いんで。でも少し、なんだよね。たとえば TRACE() の代わりに AtlTrace() が用意されてたりと、結構至れり尽くせりだったり。だから、作るとしてもほんのちょっとかも。これ、公開するかどうかは未定。
 
・でわまたっ!
透明1ドットイメージ
 
2000/12/18 (Mon)
・今日はお休み〜。
 
・ぐはっ、お便り来てたのね! お便り紹介は明日します〜。
透明1ドットイメージ
 
2000/12/19 (Tue)
・今日はお便り紹介。まずは昨日送られてきたのから。
 
透明1ドットイメージ
透明1ドットイメージ
 質問があります。
 VC++6.0でお絵かきツールもどきを作成しているのですが、MDIビューに表示してあるデータ(Polyline等で描画したデータ)をビットマップファイルとしてセーブしたいのですが、可能なのでしょうか?(簡単に言うとデバイスコンテキストで書いているデータをビットマップにおとしたいのです。)
 よろしくお願いいたします。
透明1ドットイメージ
透明1ドットイメージ
 
・可能でーす。基本は MSDN の SAVEBMP.C ってページにある方法でできます。このページのコードがちょっと古いのだったんで、ちょっと書き換えてみました。でもエラー処理してないので注意(汗)。ちょっと中途半端に書き換えちゃったかなー、元のコードの方が分かりやすいかもしんない。
 
BOOL SaveBitmapFile( HDC p_hDC, LPCTSTR p_pchFileName )
{ 
    HBITMAP hBmp = (HBITMAP)GetCurrentObject( p_hDC, OBJ_BITMAP );
 
    BITMAPINFO  stBmpInfo; 
    stBmpInfo.bmiHeader.biSize = sizeof( stBmpInfo.bmiHeader );
    stBmpInfo.bmiHeader.biBitCount = 0;
    GetDIBits( p_hDC, hBmp, 0, 0, NULL, &stBmpInfo, DIB_RGB_COLORS );
 
    ULONG iBmpInfoSize; 
    switch( stBmpInfo.bmiHeader.biBitCount )
    { 
        case 24:
            iBmpInfoSize = sizeof(BITMAPINFOHEADER); 
            break;
        case 16: 
        case 32:
            iBmpInfoSize = sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3; 
            break;
        default:
            iBmpInfoSize = sizeof(BITMAPINFOHEADER)
                    + sizeof(RGBQUAD)
                    * ( 1 << stBmpInfo.bmiHeader.biBitCount ); 
            break;
    } 
 
    PBITMAPINFO pstBmpInfo;
    if( iBmpInfoSize != sizeof(BITMAPINFOHEADER) ) 
    { 
        pstBmpInfo = (PBITMAPINFO)GlobalAlloc
                    ( GMEM_FIXED | GMEM_ZEROINIT, iBmpInfoSize );
        PBYTE pbtBmpInfoDest
            = (PBYTE)pstBmpInfo; 
        PBYTE pbtBmpInfoSrc
            = (PBYTE)&stBmpInfo; 
        ULONG iSizeTmp
            = sizeof( BITMAPINFOHEADER );
 
        while( iSizeTmp-- ) 
        { 
            *( ( pbtBmpInfoDest )++ ) = *( ( pbtBmpInfoSrc )++ ); 
        } 
    } 

    HANDLE hFile
        = CreateFile
                ( p_pchFileName, GENERIC_WRITE, 0
                , NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE 
                , NULL );
 
    BITMAPFILEHEADER stBmpFileHder; 
    stBmpFileHder.bfType = 0x4D42; // 'BM' 
    stBmpFileHder.bfSize
        = sizeof(BITMAPFILEHEADER)
        + sizeof(BITMAPINFOHEADER)
        + iBmpInfoSize
        + pstBmpInfo->bmiHeader.biSizeImage; 
    stBmpFileHder.bfReserved1 = 0;
    stBmpFileHder.bfReserved2 = 0; 
    stBmpFileHder.bfOffBits
        = sizeof(BITMAPFILEHEADER) + iBmpInfoSize; 
 
    DWORD dRet;
    WriteFile
        ( hFile, (LPCVOID)&stBmpFileHder
        , sizeof(BITMAPFILEHEADER), &dRet, NULL );
 
    PBYTE pBits
        = (PBYTE)GlobalAlloc
                ( GMEM_FIXED | GMEM_ZEROINIT
                , stBmpInfo.bmiHeader.biSizeImage );

    HBITMAP hBmpOld; 
    HBITMAP hTmpBmp
        = CreateCompatibleBitmap
            ( p_hDC
            , pstBmpInfo->bmiHeader.biWidth
            , pstBmpInfo->bmiHeader.biHeight );
    hBmpOld = (HBITMAP)SelectObject( p_hDC, hTmpBmp ); 
    GetDIBits
        ( p_hDC, hBmp, 0, pstBmpInfo->bmiHeader.biHeight
        , (LPSTR)pBits, pstBmpInfo, DIB_RGB_COLORS );

    WriteFile
        ( hFile, (LPCVOID)pstBmpInfo
        , iBmpInfoSize, &dRet, NULL );
 
    WriteFile( hFile, (LPCVOID)pBits
        , pstBmpInfo->bmiHeader.biSizeImage
        , &dRet, NULL );
 
    SelectObject( p_hDC, hBmpOld ); 
    DeleteObject( hTmpBmp ); 
    CloseHandle( hFile ); 
    GlobalFree( pstBmpInfo ); 
    GlobalFree( pBits ); 
    return TRUE;
} 
 

// 呼び出し例。 DC が張り付いているビュークラスのメンバ関数です。
void CMy20001219View::On1() 
{
    // TODO: この位置にコマンド ハンドラ用のコードを追加してください
    CDC *pDC = GetDC();
    CDC cMemDC;
    cMemDC.CreateCompatibleDC( pDC );
    CBitmap cMemBmp;
    cMemBmp.CreateCompatibleBitmap( pDC, 100, 100 );
    cMemDC.SelectObject( cMemBmp );
    cMemDC.BitBlt( 0, 0, 100, 100, pDC, 0, 0, SRCCOPY );
    SaveBitmapFile( cMemDC.GetSafeHdc(), "AAAAA.bmp" );
}
	
 
・な、ながっ!(汗) 基本は BITMAPINFO とかの構造体を用意して、ファイルに書き込んでってくだけ。だから、構造体の設定とかがしっかりできれば問題ないはず。あと、 SAVEBMP.C の例だとそのままだとうまくいかなかったんで、メモリ DC を作ってから渡してます。この部分は上の関数に埋め込んでもいいかも。ってゆーかもしかしたらこれいらないのかもなー、もちっと解析しないとちょっと分かんないです。……いやね、この処理って今回初めて試したんで(汗)。
 
・もひとつお便り!
 
透明1ドットイメージ
透明1ドットイメージ
 こんにちは。またお世話になります。
 実験に使うアプリを作ることになり、その中でwave ディバイスにAPI でアクセスする必要が出てきました。大きなファイルを扱うので、自前でバッファリングするようにしました。
 すると、バッファリングしたデータを少しずつディバイスに送らなければならなくなりました。ところが、waveOutwrite は、データを置くとすぐに関数から抜けてしまううえ、データを続けて送ると和音状態になってしまうので、一応WOM_DONE メッセージが発行されるときにイベントを送ってくるようにして出力の終わりを感知するようにしました。
 問題というのは、その際、ぶちぶちという音の途切れが聞こえてくることです。これを解決する方法はないでしょうか。よろしくお願いします。
透明1ドットイメージ
透明1ドットイメージ
 
・おひさです〜。えーっと、わて自身はこの辺はそれほど知識ないので、リンク紹介します。まず こちら。 waveOutWrite() の使用例です。このコードを使うときには、 #pragma comment( lib,"winmm.lib" ) と #include <mmsystem.h> を最初に加えて、 WaveProc() を宣言しておいて、 Animate() と Animate2() を呼ばないようにして、 const int LOOPMAX = 1; って感じに定義しといて、開くファイルを c:\\windows\\media\\tada.wav にして、あと HWND hwnd って定義してこの hwnd にトップウィンドウのハンドルを入れれば、コンパイル通ると思います。
 
・この例だと、途切れずにうまく続いているんで、これを参考にすればうまくいくかも。あと、なんか「ダブルバッファ」って言って、ふたつのバッファを入れ替えていく方法があるみたいです。アニメーションではよく使う方法だけど、音声でもこういうのあるんだなー。その例はこちら。でもこっちは試してないんで動くかどうか不明(汗)。
 
・でわまたっ!
透明1ドットイメージ
 
2000/12/20 (Wed)
・今日もお便り紹介!
 
透明1ドットイメージ
透明1ドットイメージ
 wave ディバイスの件なのですが、どうにか解決しました。ディバイスに何回かに分けてデータを送る方法としては、
 
1.wave ディバイスをオープンする
2.wave データの入ったメモリ領域を確保する
3.そのデータのためのWAVWHDR 構造体を生成する
4.waveOutPrepareHeader() でその構造体をディバイスに送る
5.waveOutWrite() でその構造体によって送りたいデータを示す
6.そのデータが処理されたのち、waveOutUnPrepareHeader() で、その構造体とディバイスを切り離す
7.必要なら、6.が行われる前に4.、5.を続けて送りたいデータに対して行っておく(当然そのデータに対してもディバイスとの切り離しを行う必要がある)
8.ディバイスを閉じる
 
 という流れでよい事がわかりました。この6.が曲者で、構造体とディバイスを切り離すまでは、データに変更が加えられないのです。僕の失敗は、このデータに変更を加えてしまっていたことでした。それと、和音状態になったのは、6.のタイミングを誤っていたのが原因でした。(つまり、構造体によって示されたメモリを書き換えていたのです。)
 
 完成した(といっても研究に使える段階にはもう1段階必要なのですが)プログラムを送ります。Play.h とPlay.cpp がディバイスを処理するクラスですので、もし上だけではわかりにくいようでしたら、ホームページに適当に切り貼りしてのっけてください。
 
 アルゴリズムとしては、1M のバッファ領域を確保してそれを8つに分け、それぞれトークン0、1、、、7と番号を振り、トークンは常にロータリー式に番号が大きくなる順に処理されます。g_BufferThread() とg_OutputThread() が、スレッドで、前者は後者を監視して、自分の読み込んだデータと後者によって処理されたデータの差がトークン二つ分以下に縮まるとデータをトークン1つ分読み込みます。後者は、前者によって読み込まれたデータを前者の読み込んだ位置を超えないようにディバイスに出力します。(つまり、後者は前者を追いかけるのです。)このとき、ディバイスが常に、今音声出力されているトークンだけでなくその次のトークンも知っているようにします。(こうすることで、滑らかな音声が出力されます。)そして、処理が終わるとともにそのトークンを解放します。そして、解放されたトークンはまた次のデータのために使えるようになります。
 
 まだまだプログラミングは経験が浅いのでわかりにくいコードになっていたらすみません。一応たくさんコメントを入れておきました。
 
 紹介してくださったホームページ、大変役に立ちました。ありがとうございました。これからもよろしくお願いいたします。
透明1ドットイメージ
透明1ドットイメージ
 
・おお、うまくいったようですね。コードは、間違ったところをペーストしてもまずいんで今回はパスします。結局、 wave なんたらな API のルールが難しいってことなんかなー。英文で書いてあるのがなおさらなのかもしんない。わてがこの手のものや、ビットマップ関係とかに手を出しづらいのもそういうとこがあるからってのもあるかもしんない。
 
・……最近プログラミングしてないね(汗)。
 
・でわまたっ!
透明1ドットイメージ
 
2000/12/21 (Thu)
・今日もお便り紹介〜。
 
透明1ドットイメージ
透明1ドットイメージ
 先日、MDIビューのデータをビットマップファイルへおとす方法をご教授いただいた者です。
 掲載されていたソースで実行したところ、以下のような場所でおちてしまいました。
 
 iBmpInfoSize とBITMAPINFOHEADERサイズの大きさ判定をしていますが、iBmpInfoSize とBITMAPINFOHEADERサイズが同じの為、pstBmpInfo->bmiHeader.biSizeImageにデータが設定されず、おちてしまいます。
 この判定は必要なのでしょうか?
 
 初心者なもので低レベルな質問で申し訳ございません。
 よろしくお願いいたします。
 
【以下掲載されていたソースの抜粋】
 
PBITMAPINFO pstBmpInfo;
if( iBmpInfoSize != sizeof(BITMAPINFOHEADER) ) 
{ 
    pstBmpInfo = (PBITMAPINFO)GlobalAlloc
                    ( GMEM_FIXED | GMEM_ZEROINIT, 
                    iBmpInfoSize );
    PBYTE pbtBmpInfoDest = (PBYTE)pstBmpInfo; 
    PBYTE pbtBmpInfoSrc = (PBYTE)&stBmpInfo; 
    ULONG iSizeTmp = sizeof( BITMAPINFOHEADER );
    while( iSizeTmp-- ) 
    { 
        *( ( pbtBmpInfoDest )++ ) = *( ( pbtBmpInfoSrc )++ ); 
    } 
 }

HANDLE hFile = CreateFile
                ( p_pchFileName, GENERIC_WRITE, 0
                , NULL, CREATE_ALWAYS,  
                FILE_ATTRIBUTE_ARCHIVE , NULL );

BITMAPFILEHEADER stBmpFileHder; 
stBmpFileHder.bfType = 0x4D42; // 'BM' 
stBmpFileHder.bfSize
    = sizeof(BITMAPFILEHEADER)
    + sizeof(BITMAPINFOHEADER)
    + iBmpInfoSize
    + pstBmpInfo->bmiHeader.biSizeImage; 
	
 
透明1ドットイメージ
透明1ドットイメージ
 
・はうぅ、ごめんなさい! これはこちらのミスでした。そのコードの前に、こういう部分があると思います。
 
    ULONG iBmpInfoSize; 
    switch( stBmpInfo.bmiHeader.biBitCount )
    { 
        case 24:
            iBmpInfoSize = sizeof(BITMAPINFOHEADER); 
            break;
        case 16: 
        case 32:
            iBmpInfoSize = sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3; 
            break;
        default:
            iBmpInfoSize = sizeof(BITMAPINFOHEADER)
                    + sizeof(RGBQUAD)
                    * ( 1 << stBmpInfo.bmiHeader.biBitCount ); 
            break;
    } 
 	
 
・その次の if は iBmpInfoSize の値で決まるんで、結局は stBmpInfo.bmiHeader.biBitCount が 24 かそれ以外か、が分岐の鍵になってます。で、 stBmpInfo.bmiHeader.biBitCount がなにかっていうと、1ピクセルに何ビット使ってるか、つまり色数を示しているんです。わての場合、画面の設定が True Coler (32ビット)なんでこの値が 32 なんだけど、たぶんそっちの環境が True Coler (24ビット)だからこの値が 24 になって、 if の中に入らないってことになっちゃってるんだと思うです。
 
・結果、 GlobalAlloc() が呼ばれないから領域が作成されなくて、 pstBmpInfo->bmiHeader.biSizeImage で無理矢理アクセスしてるからアクセスバイオレーションしちゃうんです。で、解決方法。 PBITMAPINFO pstBmpInfo; の行を次のように書き換えてください。
 
    PBITMAPINFO pstBmpInfo = &stBmpInfo;	// こう書き換えてください。
    if( iBmpInfoSize != sizeof(BITMAPINFOHEADER) ) 	// 以下はそのまま。
//  ...
	
 
・つまり pstBmpInfo に初期値として stBmpInfo のアドレスを入れておけばOK。これ、元のコード( SAVEBMP.C )にはありました(大汗)。教訓1。コードを書き換える時には最新の注意を払おう。教訓2。テストはいろんな環境で行おう。混乱させて申し訳なかったです。やっぱ SAVEBMP.C を元に調べていった方がいいかもしんない……。
 
・でわまたっ!
透明1ドットイメージ
 
2000/12/22 (Fri)
・むむむ、プログラミング辞書に「晴餅 弉勿忤 箕荷」なるものが送られてきた。いよいよかぶスタに中国読者が!? と思ったら文字化けらしい(汗)。「晴餅」は「タイプ」、「弉勿忤」は「ライブラリ」、「箕荷」は「ファイル」を半角カタカナで打ち込んだものらしいです。
 
・今日のお便り。
 
透明1ドットイメージ
透明1ドットイメージ
 こんばんは、12/20の鏑矢の憂鬱の続きなのですが、私の作ったプログラムが、私のVAIO では動くにもかかわらず、Win98 ではスレッドの部分が動きません。また、小さいデータを処理するためにスレッドを使わないルーチンも用意していたのですが、そちらもwave デバイスが開けないというエラーになってしまいました。Win98 で動いて2000 で駄目だというのはたまに聞くのですが、逆の現象は初めてです。
 質問なのですが、鏑矢さんはNT 系で動いてWin98 で動かないという現象を耳にされたことがありますでしょうか。
 もしよければ教えてください。お願いします。
 
P.S. 先日お送りしたプログラムなのですが、差し出がましい事かもしれないというのはもちろん承知でしたが、質問しておいて解決したことをお知らせしないというのはルール違反だと思いましたので、送らせていただきました。お気に触られたかもしれません。お許しください。
透明1ドットイメージ
透明1ドットイメージ
 
・プログラム送ってOKです。ってゆーか、送らないよりは送ってくれた方が解決できる可能性大です(爆)。説明聞くよりもコード見た方が分かるってことも多いし。 WinNT で動いて Win98 動かないってことも結構あります。たとえば Unicode まわりの実装は WinNT にしかされてないとか。で、今回のはちょっとした実装の違いによるものみたいです。こうすれば動くようになりました(うちの環境は Win98 なので)。
 
    DWORD dwThreadId;
    CreateThread
        (0, 0, (LPTHREAD_START_ROUTINE)g_BufferThread
        , 0, 0, &dwThreadId);
	
 
・つまり第5引数でスレッド ID を受け取らなきゃダメってことみたいです。 WinNT の CreateThread() はこれが NULL でも動くけど、 Win98 の方はエラーになるって実装みたいです。こーゆー細かいとこの違いが結構大変だったり。うちのフリーウェアもそういうとこありそうだなぁ(汗)。
 
・あと、 CreateThread() で呼んでる部分がちょっとアヤシイかな。2度連続で呼んでるけど、こうしちゃうと g_BufferThread() で処理してる途中に g_OutputThread() が走っちゃうんでまずそう。ちゃんと動いてはいるんだけど(爆)。 CreateThread() でひとつだけ関数を呼んで、その関数で最初に g_BufferThread() を、次に g_OutputThread() って形がいいと思うです。
 
・あと CreateThread() の第3引数が g_BufferThread() とかの第1引数として渡されるんで、これに g_ThreadData のポインタを渡すようにすれば g_BufferThread() で使うことができます。これでグローバル変数になってる g_ThreadData をローカル変数にできるんですっきりしそう。その辺やってみてねー。
 
・もひとつお便り。
 
透明1ドットイメージ
透明1ドットイメージ
 すみません、わからないことがあります。教えていただければ幸いです。もし、以前同じような質問がありましたらすみません。探します。よろしくお願いします。
 現象:オリジナルのDLLを作成(以前LIB形式で作成したものをコンバート)し、それを以下の構文で読み込むプログラムを作成しました。結果、DLL内の関数で処理されることはされましたが、どうやらWindows98の環境ではこのアプリケーション終了したしばらく後に『このアプリケーションは不正な処理を行なったので・・・』とメッセージが表示されてしまうみたいです。(NT4.0はOKでした。それ以外はテストできてません。)調べたところ、そのメッセージは以下の””が原因で出ているようなのです。この現象を回避する方法はあるでしょうか?もしくはDLL内のどの辺が悪いのかわかりますでしょうか?
 ちなみにデバックを行なうと、添付ファイルのようなメッセージが表示されました。
 
プログラム:
PREVPROC pRevProc = NULL;

HINSTANCE hRevLib = AfxLoadLibrary( _T( DLL ) );
if( hRevLib != NULL ){
    pRevProc
         = (PREVPROC)::GetProcAddress( hRevLib,"DLL_main_program" );
    if( pRevProc != NULL ){
        if ( (pRevProc( &str_rev1 ))==0 ){ 
//                    ・・・この行が悪さをしてるみたいです。
        }
        else{
        }
            AfxFreeLibrary( hRevLib );
        }
    else{
        AfxFreeLibrary( hRevLib );
    }
}
	
 
注記:
「DLL_main_program」は"short型"の関数で、引数に構造体"STR_REV"(自作)型の”str_rev1”(のポインタ)が渡されます。またDLL読み込み用に、typedef short (CALLBACK* PREVPROC)( STR_REV* );は宣言されています。
 わがままですみません。よろしくお願いします。
透明1ドットイメージ
透明1ドットイメージ
 
・いえいえ、このページは質問してもらわないとお休みになっちゃうんで(爆)。で、添付ファイルの画像を見ると、 ASSERT してるみたいですね。
 
Debug Assertion Failed!

Program: reverse.exe
File: fopen.c
Line: 54

Expression *file != _T( '\0' )
(以下略)
	
 
・このダイアログは、 MFC の ASSERT ってマクロが出力するもので、これでだいたい原因が分かるようになってます。ここに書いてあるとおり、 fopen.c の54行目で *file != _T( '\0' ) を評価して、これが FALSE だったんで ASSERT しています。これは実際に fopen.c の54行目を見た方が早いかも。
 
・この ASSERT が言わんとしてることは「ファイル名を格納してる文字配列が空だよ」ってこと。つまり1文字目に終端文字が入っちゃってるんです。 DLL の中とかで fopen() を呼んでるところを探して、その部分の前に「文字配列が空か」のチェックをするようにすればこの ASSERT は発生しないと思います。ただ、これが「アプリを終了してからエラーが発生」の原因かどうかは不明。もちっと調べた方がいいかも。
 
・でわまたっ!
透明1ドットイメージ
 
2000/12/23 (Sat)
・今日もお便り紹介ッ!
 
透明1ドットイメージ
透明1ドットイメージ
 早速のご回答ありがとうございます。  ですが、謝らなければなりません。大変申し訳ないのですが、添付したファイルが間違っておりました。
 正しくは、このファイルなのです。
 よく確認せず送付してしまったことをお詫びいたします。
 すみませんでした。
透明1ドットイメージ
透明1ドットイメージ
 
・あらま、そうでしたか。そのエラーダイアログはというと……
 
Debug Error!

Program: ADFY.exe
Module:
File i386\chkesp.c
Line: 42

The value of ESP was not properly saved across a function call. 
This is usually a result of calling a function declared with one calling 
converiton with a function pointer declared with different calling convertion.
	
 
・っていうエラーが出てますね。この原因は、おそらく関数ポインタを typedef してる部分に CALLBACK を付けているのが原因だと思います。例を挙げておきます。
 
void Called( int p_i )
{
}

void Test()
{
    typedef void (CALLBACK *type_Called)( int );
    type_Called pfnCalled = (type_Called)Called;
    pfnCalled( 100 );
}
	
 
・ただの関数ポインタを呼び出すときに、 CALLBACK を指定しちゃうと、レジスタの操作が変になって、それを検知して上のエラーが出る仕組みになってます。おそらく、 DLL の方は CALLBACK 指定が付いていないんだと思います。呼び出し規約が違うとレジスタへの渡し方とか変わってきちゃうからこういうエラーになっちゃうんで、 Exe と DLL で、 CALLBACK を付けるか付けないか、どっちかに統一すればうまくいくと思うです。
 
・もひとつツッコミ!
 
透明1ドットイメージ
透明1ドットイメージ
  12/22の続きです。
 なるほど、CreateThread() で、&hThread を記述しなかったのが原因だったのですね。どうせ使わない値だから、NULL でいいと思っていました。ただ、今考えると、エラーを出してほしかったですね。同じWin32 だから、統一してほしいところです。
 それと、CreateThread() を2回呼んでいるのはそういうアルゴリズムだからです。バッファリング用スレッドと出力用スレッドは、互いに相手の様子を監視しながら自立して自分の働きを決めるようになっています。というか、1M のバッファを使いまわすので、データがすべて処理されるまで2つのスレッドは存在し続ける必要があります。
 また質問ができてしまったのですが、スレッドに渡す変数はクラスメンバにしてよいのでしょうか。C MAGAZINE は、static にしなければ駄目だし、コンパイルオプションで最適化をデフォルトにしなければ駄目だという風に書いていたので、それならいっそのことグローバルでvolatile の方がいいと思ってそうしました。この辺は、どうなっているのでしょうか。よろしくお願いします。
透明1ドットイメージ
透明1ドットイメージ
 
・なるほど、グローバル変数の値をフラグにして同期処理をしてるんですね。一方のスレッドでデータを読み込み、もう一方で音声出力、これなら読み込みつつ出力できるわけですね。スレッドに渡す変数は、スレッドが走ってる間寿命がありさえすれば、基本的に何でも構わない……はず(汗)。最適化が不具合の原因になる、っていうのはマルチスレッドに限らずよく聞く話だけどね。
 
・あるひとつのプロセスの中では、スレッドとメモリ領域は基本的に無関係だから、変数に関してはそれほど神経質になる必要はないと思うです。要は、スレッドが走ってる間に、その変数が移動しなきゃいいわけで、メンバ変数だからころころ位置が変わるなんてこたないんで大丈夫でしょう。たーだ、「うまく動いているコードには手を加えない方がいい」って格言もあるからなー。
 
・でわまたっ!
透明1ドットイメージ
 
2000/12/24 (Sun)
・今日もお便り紹介!
 
透明1ドットイメージ
透明1ドットイメージ
 こんにちわ
 
 ダイアログベースでレポート型のリストビューを作成しています。
 リストビューのアイテムテキストの編集を出来るようにしたいと思っているのですがよく分からない部分があります。カラムの1列目は編集できるようになったのですが2列目を編集したい場合はどのようにしたらいいのでしょうか?
 
 自分のやり方はCListCtrl::EditLabelを使用してラベルを編集するエデットボックスを呼び出して編集状態にして編集後に、CListCtrl::GetEditControlでエデットの編集内容を取得してそれを反映させています。
 
 2列目以降を編集したい場合は、拡張スタイルなどを指定必要があるのでしょうか。
 知っていたら教えて欲しいのですがよろしくお願いします。
透明1ドットイメージ
透明1ドットイメージ
 
・つまり、エクスプローラーで言うと各ファイルの「サイズ」とか「ファイルの種類」の項目も、クリックしてエディットボックス状態にして書き込めるようにしたいってことですよね。ってゆーか、そういう機能付いてるリストコントロールってあるのかな(汗)。たぶん、デフォルトのままじゃ無理なんじゃないかなと思います。
 
・実現するとすれば、クリックしたときにエディットボックスそこに作成して入力状態にする、っていうのがあるかな。入力し終えたらエディットボックスを消して反映させる。つまり、リストコントロールがしてることを自前ですればいいかなってこと。めんどそうだけど(汗)。あとは、項目をクリックしたらダイアログを表示するようにして、全列まとめて設定できるようにするとか。これはユーザーの方が面倒かもしんない(汗)。
 
・でわまたっ!
透明1ドットイメージ
 
2000/12/25 (Mon)
・最近全然プログラミングしてないなー(汗)。そんな時はお便りが頼り( delete [] Zabuton )。とゆーわけで今日のお便り。
 
透明1ドットイメージ
透明1ドットイメージ
 質問があります。
 MDIビューの右上に表示されている×ボタンやアイコン化ボタン等を非表示にする方法がありましたら教えて下さい。よろしくお願いいたします。
透明1ドットイメージ
透明1ドットイメージ
 
・ボタンを消すだけなら、ウィンドウスタイルから WS_SYSMENU を取り除くだけでOK。たとえばこんな感じ( SWP_DRAWFRAME のこと教えてもらってて助かった……)。
 
	AfxGetMainWnd()->ModifyStyle
			( WS_SYSMENU, 0, SWP_DRAWFRAME );
	
 
・だけどー、これだとシステムメニューのアイコン(タイトルバー左端のアイコン。正式名称は「コントロールメニューボックス」)がなくなっちゃうんだよねー。これなくなるとまずい場合には、タイトルバーの文字列を空にして、 GetWindowDC() でウィンドウ全体のデバイスコンテキストを取得して、自前でアイコンとキャプションを書き込んで、アイコンをクリックしたらメニューを表示する、ってしないとあかんです。ちょっとめんどいかも。
 
・でわまたっ!
透明1ドットイメージ
 
2000/12/26 (Tue)
・今日もお便り紹介〜。
 
透明1ドットイメージ
透明1ドットイメージ
 早速の回答、ありがとうございました。
 ご指摘のとおり、CALLBACK関数の宣言部において
 
typedef short (CALLBACK * PREVPROC)(STR_REV *)
 
を、
 
typedef short ( * PREVPROC)(STR_REV *)
 
 として実行したら、エラーも出ずにデバックが行なえました。また、Windows98も問 題なく処理されました。
 ありがとうございました。とても助かりました。
 これからもよろしくお願いします。
透明1ドットイメージ
透明1ドットイメージ
 
・おおっ、うまくいったみたいですね。あのエラーコード、前に一度経験してたんで見つけだせました。メンバ関数ポインタを普通の関数として呼び出したりとか色々してたからなー(汗)。またなんかあったら訊きにきてねん。
 
・もひとつお便り。
 
透明1ドットイメージ
透明1ドットイメージ
 「Win32 Console Application」でプロジェクトで作成したEXEを起動した時にDOS窓が表示されてしまいますが、非表示にできる方法はあるのでしょうか? もしくは、アイコン化できますか?
 ご教授ください。
 よろしくお願いいたします。
透明1ドットイメージ
透明1ドットイメージ
 
・起動方法によるかなー。 CreateProcess() で Exe を実行するんなら、 STARTUPINFO の設定を変更すればOK。たとえばこんな感じ。
 
    STARTUPINFO stStartupInfo;
    memset( &stStartupInfo, 0, sizeof(stStartupInfo) ); 
    stStartupInfo.cb          = sizeof( stStartupInfo ); 
    stStartupInfo.dwFlags     = STARTF_USESHOWWINDOW;
    stStartupInfo.wShowWindow = SW_HIDE;

    PROCESS_INFORMATION stProcessInfo;
    CreateProcess
        ( "C:\\WINDOWS\\COMMAND.COM", NULL, NULL, NULL
        , FALSE, CREATE_NEW_CONSOLE, NULL, NULL
        , &stStartupInfo, &stProcessInfo );
	
 
・自前で起動できない場合には、ちょっとめんどいかも。 DOS 窓のウィンドウ名は実行ファイル名から .exe を取り除いたもの、ウィンドウクラスは tty なんで、それを EnumWindows() で探し出してそのウィンドウを ShowWindow() で SW_HIDE にしちゃえばOK。
 
・一瞬でも表示されちゃいけないって場合には、システムフックとして CBT フックをセットして、表示されつつあるウィンドウをチェックするって方法を取らなきゃダメかも。そうなるとちょっと難しいね。もしその Exe が自前で作ったものなら、ウィンドウアプリとして作って非表示化させた方が後々融通利かせやすいと思うです。
 
・でわまたっ!
透明1ドットイメージ
 
2000/12/27 (Wed)
・今日もお便り紹介〜。
 
透明1ドットイメージ
透明1ドットイメージ
 こんにちは。
 教えていただきたいことがあるのですが。
 「Win32 Console Application」で作成したプログラムから、DOSコマンドを実行するにはどうしたらよいのでしょうか?
 初歩的(?)な質問で、申し訳ありません。
透明1ドットイメージ
透明1ドットイメージ
 
・ DOS コマンドは、 Windows\command.com ってアプリが受け持ってて、たとえば command.com /c del D:\A.txt とかすればOK。これを CreateProcess() とかで実行すればうまくいきます。たとえばこんな感じ。
 
    STARTUPINFO stStartupInfo;
    memset( &stStartupInfo, 0, sizeof(stStartupInfo) ); 
    stStartupInfo.cb          = sizeof( stStartupInfo ); 
    stStartupInfo.dwFlags     = STARTF_USESHOWWINDOW;
    stStartupInfo.wShowWindow = SW_HIDE;
    
    PROCESS_INFORMATION stProcessInfo;
    CreateProcess
        ( NULL
        , "C:\\WINDOWS\\COMMAND.COM /c del D:\\A.txt"
        , NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL
        , NULL, &stStartupInfo, &stProcessInfo );
	
 
・なんか昨日のとすごく似てるな(爆)。コマンドライン全体を第2引数に入れなきゃいけない、ってことに気付くまでにえらい時間が掛かってしまった……。ま、こんな感じに CreateProcess() の第2引数に command.com と実行したいコマンドを書き込めばうまくいくと思うです。
 
・でわまたっ!
透明1ドットイメージ
 
2000/12/28 (Thu)
・最近イラストとゲームしかしてないよーな……ではお便り紹介〜。
 
透明1ドットイメージ
透明1ドットイメージ
 おはようございます。
 質問なのですが、シェルエクステンションの部分を読み::SHBrowseForFolderで「フォルダ選択ダイアログ」を表示する方法はなんとなく理解できたのですがこれをツリービューでデスクトップを基として作成するにはどうしたらよいのでしょうか?
透明1ドットイメージ
透明1ドットイメージ
 
・つまりエクスプローラーの左ペインみたいなのを実装したいってことですよね。それ、わても知りたい(泣)。これを簡単に実装する方法は、どうやらなさそうなんですよねー、残念ながら。あったら誰か教えて(汗)。
 
・似たようのなのとしては、ダイアログのサイズを変えたり、子ウィンドウとして上に貼り付けたりとかすれば一応それらしくは見えるんだけど、限界あるかなー。ホントにそのまんまのを作りたい場合には、シェルエクステンションの IShellFolder とか駆使しないといけないかも。
 
・でわまたっ!
透明1ドットイメージ
 
2000/12/29 (Fri)
・今日はお休み〜。
透明1ドットイメージ
 
2000/12/30 (Sat)
・今日もお休みです。
透明1ドットイメージ
 
2000/12/31 (Sun)
・おととい昨日とお休みだったのになぜか今日はあります(爆)。しかもお便りじゃないし。卒業論文でインターネット上を片っ端から漁る予定なんで、そのためのアプリをいっそ作ってしまおうと。卒論までに間に合うかどうかは不明(汗)。まー気合い入れて作ればあと2日もあればできちゃうでしょう。
 
・ダウンロードする部分はもうできてたんで、検索エンジン google に検索パラメーターを渡して検索結果を取得するって部分を昨日の夜と今日作ってました。こういうのって、別ポート開いて特別な方法で送信するんだと思ってたら、ただ URL にパラメーターくっつけるだけで良かったのね。その辺をブラウザがやってたんだなー。
 
・のっけから漢字を URL に埋め込むためのエンコードにはまる(爆)。単に「あ」なら Shift-JIS で「 0x82A0 」、1バイトずつに分けて & をプレフィックスにして「 %82%A0 」でOK。文字コードとかバイトオーダーとか考えなくていいらしい(汗)。 isalnum() とか使って分類して置き換えて完成。
 
・あとは google のパラメーターの解析をして、それをリクエストに加えて、あとは検索文字列をエンコードしたのをくっつければOK。おー検索結果が出てきた! それにしても、 http://www.google.com/ で日本語ページが出てくるのはどういう仕組みだろう(汗)。まーパラメーターで hl=ja ってすればいいんで問題ないんだけどね。とりあえず、このアプリは速攻で作ってしまおう。アイコンとかももう描いたし〜。
 
・でわまたっ!
 
 
(C)KAB-studio 2000 ALL RIGHTS RESERVED.