none
DLLを使った、多プロセス間でのメモリ共有(変数データ)の練習プログラム RRS feed

  • 質問

  • VS 2008 でDLL生成前ソースファイル内で、定義された変数データ(LONG)を、多プロセスからアクセスし、
    各プロセスが、変数データ(LONG)をインクリメントして、表示するダイアログボックスのプログラムを書いています。

    DLL生成前ソースファイル sharedll.cpp の一部は、↓で

    #include <windows.h>
    
    // -----------------------------------------------------------------------------------
    #pragma data_seg( "foo" )
    LONG instanceCounter = 0;
    #pragma data_seg()
    
    // 省略


    追加したDEFファイル sharedll.def は、↓です。

    LIBRARY    "sharedll"
    
    SECTIONS
        foo    READ WRITE SHARED

    DLL 生成プロジェクト名は、「"shareVarDll"」だったので、リビルドすると
    Release フォルダに shareVarDll.dll と shareVarDll.lib が生成されました。


    次に、
    DLL内の変数にアクセスするダイアログプログラム shareVar.exe を下の手順で作成しました。

    プロジェクト名「"shareVar"」
    1. shareVarDll.lib をプロジェクトに[追加] - [既存の項目...] で追加。

    2. 実行プログラムファイル pgm.cpp は、下記です。

    # include <windows.h>
    # include "resource.h"
    
    
    //----------------------------------------------------------------------------
    //  DLL エクスポート関数プロトタイプ宣言
    //
    WORD __declspec(dllimport) __stdcall getInstanse( void );
    
    
    //----------------------------------------------------------------------------
    //  Dialogboxプロシージャ プロトタイプ宣言
    //
    BOOL CALLBACK dlgProc( HWND , UINT , WPARAM , LPARAM );
    
    
    // ---------------------------------------------------------------------------
    // WinMain
    //
    int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
                                            LPSTR lpCmdLine, int nCmdShow)
    {
        HWND hDlg;
        MSG  msg;
       
        // ダイアログボックスの生成
        hDlg = CreateDialog( hInstance, L"IDD_DIALOG1", HWND_DESKTOP, (DLGPROC)dlgProc );
        if ( hDlg == 0 )
        {
            return FALSE;
        }
       
        while ( GetMessage( &msg, NULL, 0, 0 ) != 0 )
        {
            if ( !IsDialogMessage( hDlg, &msg ) )
            {
                TranslateMessage( &msg );
                DispatchMessage( &msg );
            }
        }
        return msg.wParam;
    }
    
    //----------------------------------------------------------------------------
    //  Dialogboxプロシージャ
    //
    BOOL CALLBACK dlgProc( HWND hDlg , UINT uMessage , WPARAM wParam , LPARAM lParam )
    {
        switch ( uMessage )
        {
            case WM_SHOWWINDOW:
                SetDlgItemInt( hDlg, IDC_EDIT1 , getInstanse() , FALSE );
                break;
               
            case WM_COMMAND:
                switch ( wParam )
                {
                    case IDC_CLOSE:
                        PostMessage( hDlg, (UINT)WM_DESTROY , (UINT)0, (LONG)0 );
                        break;
                       
                }
                break;
               
            case WM_DESTROY:
                PostQuitMessage( 0 );
                return TRUE;
               
        }
        return FALSE;     // メッセージを処理しない場合はFALSEを返す
    }


    3. [構成マネージャ]で構成を"Release"にして、リビルド。
            shareVar.exe が作成された。


    そして、shareVar.exe と shareVarDll.dll を同じフォルダに置いて、shareVar.exe を実行してみました。(ダブルクリック)
    すると、
    「コンポーネントが見つかりません」エラー、エラー内容は、↓でした。
    "sharedll.dll が見つからなかったため、このアプリケーションを開始できませんでした。アプリケーションをいんすとーるし直すとこの問題は解決される場合があります。"


    なぜ "shareVarDll.dll" でなく "sharedll.dll" を見つけようとするのでしょう?


    また、
    DLLを生成するしなおす際に、
    プロジェクトの プロパティ ページで、
    [構成プロパティ] - [リンカ] - [全般] の「出力ファイル」を "$(OutDir)\sharedll.dll" に指定し[適用]し、

    ビルドすると。"sharedll.dll" と "sharedll.lib" が生成させましたので、
    呼び出し側プロジェクト「"shareVar"」に
    sharedll.lib を[追加] - [既存の項目...] して、

    "Debug"構成でビルドし直した、shareVar.exe を、"sharedll.dll" と同じフォルダでデバッグしたら、
    pgm.cpp の
        hDlg = CreateDialog( hInstance, L"IDD_DIALOG1", HWND_DESKTOP, (DLGPROC)dlgProc );
    の返り値が
    "0x00000000" で、プログラムを終了するはめになります。

    分からないことは、大きく2つあり、
    1. なぜ、実行プログラム"shareVar.exe" は、"shareVarDll.dll" でなく、"sharedll.dll" を見つけようとするのか?

    2. なぜ、CreateDialog( hInstance, L"IDD_DIALOG1", HWND_DESKTOP, (DLGPROC)dlgProc ); に失敗するのか?

    です。

    長文を最後まで読んで頂き、とてもありがたく思います。

    どんなことでも教えて頂けたらうれしいです。よろしくお願いします。。



    2010年1月11日 14:46

回答

  • >1.
    >LIBRARY    "sharedll"
    これが原因で発生した現象だと考えられます。
    「出力ファイル」で指定されているファイル名と異なる場合、以下Warningが発生します。

      Warning 1 warning LNK4070: /OUT:sharedll.dll directive in .EXP differs from output filename 「出力ファイル」 ; ignoring directive

    結果、exeではLIBRARYで指定されたモジュール名が使用され、
    DLLのBuildでは「出力ファイル」で指定されているファイル名で出力され、整合性が取れなくなります。
    (dumpbin /imports shareVar.exeで確認できますよ)

    WarningはErrorではないのでBuildは続行されますが、取り除かないと実行時にErrorになるWarningもあります。
    原則Warningはすべて取り除くべきしょう。

    >2.
    GetLastErrorで何故失敗するか確認してください。
    おそらく、L"IDD_DIALOG1" Dialog Resourceが見つからないのではないでしょうか。

    >多プロセスからアクセスし、各プロセスが、変数データ(LONG)をインクリメントして
    排他制御を行わないと、意図しない結果になることがあります。
    InterlockedIncrementによる制御を検討したほうが良いでしょう。
    • 編集済み kozz 2010年1月12日 1:27 記載ミス
    • 回答としてマーク fedoracche 2010年1月12日 2:52
    2010年1月12日 1:13

すべての返信

  • 何がわかってなくて、何を知りたいのか、ご自身で把握していますか?
    もしそうなら「DLLを使った、多プロセス間でのメモリ共有(変数データ)の練習プログラム」というタイトルは知りたい内容に対して適切ですか?
    2010年1月11日 15:48
  • なぜ "shareVarDll.dll" でなく "sharedll.dll" を見つけようとするのでしょう?

    > 追加したDEFファイル sharedll.def は、↓です。
    > LIBRARY    "sharedll"
    ここで、作成するDLLの名前を指定しているからではないでしょうか?

    ヘルプで、LIBRARY を検索すれば説明が見つかりました。

    2010年1月12日 0:02
  • ご回答ありがとうございます。

    DEFファイルの「LIBRARY」文で指定するのですね。


    ([ヘルプ] - [検索] で、「LIBRAR」を[検索]ボタンで実行したんですが、DEFファイルに関する文法は見つけることができませんでした。)
    2010年1月12日 1:06
  • ご指摘ありがとうございます。

    確かにタイトルは、適切ではなかっと、今思います。

    質問を書着だしたときは、何が分からないのかはっきりしなかっのですが、最後の方で分からないことが絞れてきました。

    タイトルを訂正してから、投稿するべきでした。
    すみませんでした。
    2010年1月12日 1:09
  • >1.
    >LIBRARY    "sharedll"
    これが原因で発生した現象だと考えられます。
    「出力ファイル」で指定されているファイル名と異なる場合、以下Warningが発生します。

      Warning 1 warning LNK4070: /OUT:sharedll.dll directive in .EXP differs from output filename 「出力ファイル」 ; ignoring directive

    結果、exeではLIBRARYで指定されたモジュール名が使用され、
    DLLのBuildでは「出力ファイル」で指定されているファイル名で出力され、整合性が取れなくなります。
    (dumpbin /imports shareVar.exeで確認できますよ)

    WarningはErrorではないのでBuildは続行されますが、取り除かないと実行時にErrorになるWarningもあります。
    原則Warningはすべて取り除くべきしょう。

    >2.
    GetLastErrorで何故失敗するか確認してください。
    おそらく、L"IDD_DIALOG1" Dialog Resourceが見つからないのではないでしょうか。

    >多プロセスからアクセスし、各プロセスが、変数データ(LONG)をインクリメントして
    排他制御を行わないと、意図しない結果になることがあります。
    InterlockedIncrementによる制御を検討したほうが良いでしょう。
    • 編集済み kozz 2010年1月12日 1:27 記載ミス
    • 回答としてマーク fedoracche 2010年1月12日 2:52
    2010年1月12日 1:13
  • 2. なぜ、CreateDialog( hInstance, L"IDD_DIALOG1", HWND_DESKTOP, (DLGPROC)dlgProc ); に失敗するのか

    これについては、まずは GetLastError() を呼んで拡張エラー情報を得るのが最初のステップかと。

     GetLastError 関数
     http://msdn.microsoft.com/ja-jp/library/cc428944.aspx

    CreateDialog() の日本語のヘルプだと、

     CreateDialog 関数
     http://msdn.microsoft.com/ja-jp/library/cc410690.aspx

    戻り値の説明に

     関数が失敗すると、NULL が返ります。拡張エラー情報を取得するには、 関数を使います。

    などと何とも意味不明なことが書かれていますが(関数って何?)、
    英語版のヘルプを見ると、

     CreateDialog Function ()
     http://msdn.microsoft.com/en-us/library/ms645434(VS.85).aspx

    もう少しましな説明が書かれています。

     If the function fails, the return value is NULL. To get extended error information, call GetLastError.

     This function typically fails for one of the following reasons:

    • an invalid parameter value
    • the system class was registered by a different module
    • The WH_CBT hook is installed and returns a failure code
    • if one of the controls in the dialog template is not registered, or its window window procedure fails WM_CREATE or WM_NCCREATE
    2010年1月12日 1:30
  • ご回答ありがとうございます。

    pgm.cpp の WinMain に↓の GetLastError()処理を追加しまして、デバッグ実行しました。

        HWND hDlg;
    MSG msg;

    LPVOID lpMsgBuf;         //追加
    SetLastError(NO_ERROR);   //追加

    // ダイアログボックスの生成
    hDlg = CreateDialog( hInstance, L"IDD_DIALOG1", HWND_DESKTOP, (DLGPROC)dlgProc );
    if ( hDlg == 0 )
    {
    FormatMessage( //エラー表示文字列作成
    FORMAT_MESSAGE_ALLOCATE_BUFFER |
    FORMAT_MESSAGE_FROM_SYSTEM |
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    GetLastError(),
    MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
    (LPTSTR) &lpMsgBuf,
    0,
    NULL
    );
    MessageBox( NULL, (LPTSTR)lpMsgBuf, NULL, MB_OK );

    LocalFree( lpMsgBuf );

    return FALSE;
    }
    結果、kozzさんの言うとおりメッセージボックスに「指定されたリソース名がイメージ ファイルに見つかりません。」と現れました。

    CreateDialog() の第2引数を、
    hDlg = CreateDialog( hInstance, MAKEINTRESOURCE(IDD_DIALOG1), HWND_DESKTOP, (DLGPROC)dlgProc );
    に変更したら、ここの部分はデバッグが通過しましたが、

    次のコード
        while
     ( GetMessage( &msg, NULL, 0, 0 ) != 0 )
    {
    if ( !IsDialogMessage( hDlg, &msg ) )
    {
    TranslateMessage( &msg );
    DispatchMessage( &msg );
    }
    }
    の最初で、デバッグが先に進まないようです。[F5]を押しても反応はありません。

    因みに、
    resource.h は↓です。
    #define IDD_DIALOG1                     101
    #define IDC_CLOSE 1001
    #define IDC_EDIT1 1002

    // Next default values for new objects
    //
    #ifdef APSTUDIO_INVOKED
    #ifndef APSTUDIO_READONLY_SYMBOLS
    #define _APS_NEXT_RESOURCE_VALUE 102
    #define _APS_NEXT_COMMAND_VALUE 40001
    #define _APS_NEXT_CONTROL_VALUE 1003
    #define _APS_NEXT_SYMED_VALUE 101
    #endif
    #endif
    shareVar.rc の一部は↓です。
    /////////////////////////////////////////////////////////////////////////////
    //
    // Dialog
    //

    IDD_DIALOG1 DIALOGEX 0, 0, 210, 153
    STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
    CAPTION "メモリのシェア"
    FONT 8, "MS Shell Dlg", 400, 0, 0x1
    BEGIN
    PUSHBUTTON "閉じる",IDC_CLOSE,79,123,50,14
    LTEXT "インスタンス数",IDC_STATIC,29,47,44,8
    EDITTEXT IDC_EDIT1,122,44,40,14,ES_AUTOHSCROLL
    END
    ダイアログボックスが表示されないのは、
    STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE ←がなかったからでした。

    これでやっと解決することができました。

    感謝いたします。
    2010年1月12日 2:52
  • >( GetMessage( &msg, NULL, 0, 0 ) != 0 )
    戻り値のCheckが間違っていますよ。
    MSDNでGetMessageの説明を読んでください。
    2010年1月12日 3:15