none
WindowsXPで稼動していたアプリケーションをWindows7で動かすと、MapViewOfFileEx関数でエラーになる RRS feed

  • 質問

  • WindowsXPで稼動しているアプリケーションを、Windows7で稼動させようとしています。
    開発環境はVisualStudio2003→VS2010となりました。

    プロセス間でメモリを共有するため、アプリケーション内で「CreateFileMapping」や「MapViewOfFileEx」関数を使用しています。
    XPで稼動していたアプリケーションをVS2010でコンパイルしなおしWindows7上で実行したところ、
    MapViewOfFileEx関数が「無効なアドレス指定です」というエラーをはき異常終了してしまいます。
    MSDNのMapViewOfFileEx関数の説明を見ると、"ビューのマッピングを開始する推奨アドレス"を指定する最後のパラメータはNULLに指定し、OSに選択させたほうがよいとあります。
    アプリケーションではこのアドレスを指定しており、ここをNULLに変更し再コンパイル→実行したところ、MapViewOfFileEx関数のエラーは発生しなくなりました。
    http://msdn.microsoft.com/en-us/library/aa366763%28VS.85%29.aspx

    また、指定しているアドレスを「0xD00000」から「0xD000000」に変更してみたところ、こちらもエラーは発生しなくなりました。


    そもそも、このアドレスに何を指定したらよいか、などのガイドはあるのでしょうか。

    また、これまで指定していたものをNULLに変更しても問題ないのでしょうか。

    よろしくお願いします。

    テストで使用しているコードは以下です。

     

    #include    <windows.h>
    #include    "tracelog.h"

    typedef struct strZCvct
    {
        UCHAR           Wtblid[4];
        UCHAR           Wprncond;
        UCHAR           Wtststop;
        UCHAR           Wtelstop;
        USHORT          Fmsgsdcd;
        USHORT          Wprinter;
    } tZCvct;

    static HANDLE   hmapfile;               /*  共有マップファイルハンドル        */
    static char     *wvctaddr_p;            /*  共有マップアドレス                */
    static HANDLE   addr_map;               /*  固定マップファイルハンドル        */
    static long     *addr_view;             /*  固定マップアドレス                */

    int MemMap( void );

    int main(int argc, char* argv[])
    {
        int rc;
        TRACE_LOG( TRC_DBG, "MEMCTL", __FILE__, __LINE__, "-----START-----" );
        rc = MemMap( );
        TRACE_LOG( TRC_DBG, "MEMCTL", __FILE__, __LINE__, "-----return(%d)-----", rc );
        return 0;
    }

    int MemMap( void )
    {
                                            /*  共有ファイルマップオブジェクト作成*/
        hmapfile = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL,
                                      PAGE_READWRITE,
                                      0,
                                      sizeof(tZCvct),
                                      "VCTTBL" );
       
        if ( !hmapfile )
        {
            {
                DWORD   dwRc;
                UCHAR   ucErrMsg[MAX_PATH];
                GetWin32APIErrMsg( &dwRc, (PCHAR)ucErrMsg, sizeof(ucErrMsg) );

                TRACE_LOG( TRC_ERR, "MEMCTL", __FILE__, __LINE__, "[CreateFileMapping()]ERRMSG:%s", ucErrMsg );
            }
            UnmapViewOfFile(addr_view);
            CloseHandle(addr_map);
            TRACE_LOG( TRC_DBG, "MEMCTL", __FILE__, __LINE__, "-----return(1)-----" );
            return(1);
        }
        TRACE_LOG( TRC_DBG, "MEMCTL", __FILE__, __LINE__, "[CreateFileMapping()]ファイルハンドル:0x%x", hmapfile );
     
                                            /*  ビューを指定アドレスでマッピング  */
        wvctaddr_p = (char *)MapViewOfFileEx( hmapfile,
                                            FILE_MAP_ALL_ACCESS,
                                            0, 0, 0,
                                            (LPVOID)0xD00000);
       
        if ( wvctaddr_p == NULL )
        {
            {
                DWORD   dwRc;
                UCHAR   ucErrMsg[MAX_PATH];
                GetWin32APIErrMsg( &dwRc, (PCHAR)ucErrMsg, sizeof(ucErrMsg) );
                TRACE_LOG( TRC_ERR, "MEMCTL", __FILE__, __LINE__, "[MapViewOfFileEx()]ERRMSG:%s", ucErrMsg );
            }
            UnmapViewOfFile(addr_view);
            CloseHandle(addr_map);
            UnmapViewOfFile(wvctaddr_p);
            CloseHandle(hmapfile);
            TRACE_LOG( TRC_DBG, "MEMCTL", __FILE__, __LINE__, "-----return(2)-----" );
            MessageBox(NULL,
                "AAAAAAA",
                "BBBBBBB",
                MB_OK|MB_SETFOREGROUND);
            return(2);
        }
       
        UnmapViewOfFile(addr_view);
        CloseHandle(addr_map);
        UnmapViewOfFile(wvctaddr_p);
        CloseHandle(hmapfile);
        TRACE_LOG( TRC_DBG, "MEMCTL", __FILE__, __LINE__, "-----return(正常)-----" );

        return 0;
    }

    2010年12月3日 3:51

回答

  • http://msdn.microsoft.com/ja-jp/library/cc430178.aspx

    ここにMapViewOfFileEx の日本語リファレンスがありますが、最後のパラメータは、呼び出し元のアドレス空間のどこかを指定とあります。

    当然ですが、メモリを割り当てるにはそのアドレスに何もないことを保証しなければなりません。VS2010とWin7という環境だと、DLLのロードアドレスがランダム化されるなど、従来とは大きく異なるか所が多々あります。

    そういうこともあり、ベースアドレスを指定するのはあまりお勧めはできません。ですが、ベースアドレスを指定しないでも問題がないか?についてはテストコードからは何もわからないため、何とも言えません。

    実際のプログラムがテストコードで wvctaddr_p にあたるポインタにアクセスするか所をすべて調査して、ベースアドレスに依存したなにかがあるか?をチェックするしかないでしょう。

    個人的には、ポインタが特定のアドレスにあることを前提としたコードというのは、将来バージョンへの移植が非常に難しくなるため、やらないほうが良いと思います。今は32bitのANSI形式で問題ないかもしれませんが(一部のPCだと、文字化け起こすとかありますけどw)、64bit時代になった時にもそのままなの?というのはありますし...


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    • 回答としてマーク 山本春海 2010年12月17日 7:55
    2010年12月3日 4:58
  • >そもそも、このアドレスに何を指定したらよいか、などのガイドはあるのでしょうか。

    ガイドという程のものではありませんが、仮想アドレス空間は断片化します。そのため、仮想アドレス空間の断片化を配慮した処理を行う必要がある場合に、ベースアドレスを指定する事があります。しかし、大抵の場合はそれを配慮する必要はありません。メモリに対してシビアな処理をApplication全体で行う場合ぐらいでしょうか。そういった配慮が必要ない場合NULLを指定することが推奨されます。

    0xD00000を指定されたのには何か理由があるのでしょうか。強い理由や裏付けがない場合は、NULLを指定するのが良いです。

    >これまで指定していたものをNULLに変更しても問題ないのでしょうか。

    OSレベルでは問題ありませんが、Applicationレベルでの確認は必要です。Process間でMemoryを共有するために利用しているとのことですので、利用しているApplication全てで動作を確認してください。処理内容によりますが、余程のことがない限り問題は起きないとは思いますので、まずはNULLにして動作検証してみてください。

    • 回答としてマーク 山本春海 2010年12月17日 7:55
    2010年12月4日 11:36

すべての返信

  • http://msdn.microsoft.com/ja-jp/library/cc430178.aspx

    ここにMapViewOfFileEx の日本語リファレンスがありますが、最後のパラメータは、呼び出し元のアドレス空間のどこかを指定とあります。

    当然ですが、メモリを割り当てるにはそのアドレスに何もないことを保証しなければなりません。VS2010とWin7という環境だと、DLLのロードアドレスがランダム化されるなど、従来とは大きく異なるか所が多々あります。

    そういうこともあり、ベースアドレスを指定するのはあまりお勧めはできません。ですが、ベースアドレスを指定しないでも問題がないか?についてはテストコードからは何もわからないため、何とも言えません。

    実際のプログラムがテストコードで wvctaddr_p にあたるポインタにアクセスするか所をすべて調査して、ベースアドレスに依存したなにかがあるか?をチェックするしかないでしょう。

    個人的には、ポインタが特定のアドレスにあることを前提としたコードというのは、将来バージョンへの移植が非常に難しくなるため、やらないほうが良いと思います。今は32bitのANSI形式で問題ないかもしれませんが(一部のPCだと、文字化け起こすとかありますけどw)、64bit時代になった時にもそのままなの?というのはありますし...


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    • 回答としてマーク 山本春海 2010年12月17日 7:55
    2010年12月3日 4:58
  • >そもそも、このアドレスに何を指定したらよいか、などのガイドはあるのでしょうか。

    ガイドという程のものではありませんが、仮想アドレス空間は断片化します。そのため、仮想アドレス空間の断片化を配慮した処理を行う必要がある場合に、ベースアドレスを指定する事があります。しかし、大抵の場合はそれを配慮する必要はありません。メモリに対してシビアな処理をApplication全体で行う場合ぐらいでしょうか。そういった配慮が必要ない場合NULLを指定することが推奨されます。

    0xD00000を指定されたのには何か理由があるのでしょうか。強い理由や裏付けがない場合は、NULLを指定するのが良いです。

    >これまで指定していたものをNULLに変更しても問題ないのでしょうか。

    OSレベルでは問題ありませんが、Applicationレベルでの確認は必要です。Process間でMemoryを共有するために利用しているとのことですので、利用しているApplication全てで動作を確認してください。処理内容によりますが、余程のことがない限り問題は起きないとは思いますので、まずはNULLにして動作検証してみてください。

    • 回答としてマーク 山本春海 2010年12月17日 7:55
    2010年12月4日 11:36
  • >とっちゃん さん

    返信ありがとうございます。

    >個人的には、ポインタが特定のアドレスにあることを前提としたコードというのは、将来バージョンへの移植が非常に難しくなるため、やらないほうが良いと思います。

    おっしゃられていること、非常に同意です。。私が直面している問題はまさにこの問題です。

     

    教えていただいたリファレンスはこちらでも見ていました。ガイドとしてはやはりこれくらいしかないのですね。

    こちらのアプリケーションとしては、NULL指定するとやはりいずれかのMapViewOfFileEx関数でエラーが発生してしまい、「0xD000000」を指定すると全てのMapViewOfFileEx関数が正常に動作するといった状況です。もう少し、アプリケーションの動きを調査していきたいと思います。

    ありがとうございました。

    2010年12月6日 0:15
  • >kozzさん

    返信ありがとうございます。

    現在のアプリケーションでは、NULL指定すると正常に稼動する箇所・しない箇所が存在する状況です。

    メモリに対してそこまでシビアな処理はしていませんので、NULL指定で稼動するよう調査・検証していきたいと思います。

    ありがとうございました。

    2010年12月6日 0:20