none
Windows Vista での GetUserName() について RRS feed

  • 質問

  • Windows Vista で WIN32API の GetUserName() を使用すると以下の条件において不可解な現象が発生します。 

     

    1.プログラムが setup.exe や uninst.exe などの Vista が自動的に昇格させると思われる名前になっている。

    2.そのプログラムが使用する dll の DLL_PROCESS_ATTACH で GetUserName() を呼び出している。

    3.そのプログラム内で GetUserName() を呼び出す。

     

    この条件がそろった場合、3.において Secur32.dll でアクセス違反が発生してしまいます。プログラム名を test.exe などに変更すると問題は発生しません。また、UAC は有効、無効にかかわらず発生します。

     

    なにか回避方法はあるでしょうか?

    2007年3月28日 4:31

回答

  • chack - Akira Inoue さん、確認までしていただきありがとうございます。

     

    DLL は変更できないので、埋め込みマニフェストにより回避するのがよさそうです。

     

    しかし、プログラム名に依存するとはいえ、こんな基本的な API の呼び出しで例外が発生するとなると Windows Vista って大丈夫なのかちょっと不安になります。

     

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

    2007年3月30日 5:30

すべての返信

  •  matuno さんからの引用
    1.プログラムが setup.exe や uninst.exe などの Vista が自動的に昇格させると思われる名前になっている。
    ...

    プログラム名を test.exe などに変更すると問題は発生しません。

     

    試してはいませんが、UAC のインストーラ検出関連で何かあるのかもしれませんね。

     

    ちなみにアプリケーションマニフェストは使用していますか?

    アプリケーションマニフェストで、

     

    <requestedExecutionLevel level="asInvoker" uiAccess="false" />

     

    を指定すると、ファイル名が setup.exe 等でもインストーラとして検出されなくなりますので、ファイル名を test.exe に変更した場合と同じ条件になるかもしれません。

     

    ちなみに、アプリケーションマニフェストについては、下記のスレッドや

    http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=1338495&SiteID=7

     

    手前みそですが、下記を参考にしてみてください。

    http://bitwiz.jp/tabid/56/EntryID/18/Default.aspx

    http://bitwiz.jp/tabid/56/EntryID/19/Default.aspx

    2007年3月28日 11:00
  •  chack - Akira Inoue さんからの引用
      

    ちなみにアプリケーションマニフェストは使用していますか?

    アプリケーションマニフェストで、

     

    <requestedExecutionLevel level="asInvoker" uiAccess="false" />

     

    を指定すると、ファイル名が setup.exe 等でもインストーラとして検出されなくなりますので、ファイル名を test.exe に変更した場合と同じ条件になるかもしれません。

     

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

     

    setup.exe.manifest を作成して、requestedExecutionLevel を全てのレベルで試してみましたが結果は同じでした。

    どうしても回避できないのであれば、プログラムの名前を変えようと思いますが、一応再現する C のサンプルコードを記載しておきます。

     

    // DLL のソースコード =========================

     

    #include <windows.h>

    #include <stdio.h>

     

    #define USERNAME_SIZE 64

     

    static TCHAR _UserName[USERNAME_SIZE];

     

    __declspec(dllexport) DWORD QueryUserName( TCHAR *Name, DWORD Size, BOOL APICalled )

    {

       DWORD result = 0;

     

      if (APICalled) {

        if (GetUserName(Name, &Size))

          result = Size;

      } else {

        strcpy(Name, _UserName);

        result = strlen(_UserName);

      }

      return result;

    }

     

    BOOL WINAPI DllMain ( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpv )

    {

      switch(dwReason) {

        case DLL_PROCESS_ATTACH:

          QueryUserName(_UserName, USERNAME_SIZE, TRUE);

          break;

      }

      return TRUE;

    }

     

    // ホストアプリケーションのソースコード ====================

     

    #include <windows.h>

    #include <stdio.h>

     

    __declspec(dllexport) DWORD QueryUserName( TCHAR *Name, DWORD Size, BOOL APICalled );

     

    #define USERNAME_SIZE 64

     

    void main(int argc, char *argv[])

    {

      TCHAR name[USERNAME_SIZE];

     

      if (QueryUserName(name, USERNAME_SIZE, TRUE) > 0)

        printf("%s\n", name);

    }

    2007年3月29日 7:28
  • ちょっと試してみましたが、確かに Vista ではエラーになりますね。

     

    で、回避策ですが、

     

    (1) ファイル名に Setup などの名前が含まれていても、UAC で権限昇格が不要な場合は、埋め込みマニフェスト

     

    <requestedExecutionLevel level="asInvoker" uiAccess="false" />

     

    を指定して、権限昇格しなければ回避できます(確認済み)。

     

    setup.exe.manifest ファイルを作成して外部マニフェストで試されたようですが、Vista の場合、外部マニフェストファイルだと上手く認識してくれない場合があります。

     

    VS2005でしたら、プロジェクトのプロパティの「マニフェストツール」-「入力と出力」で「追加のマニフェストファイル」に requestedExecutionLevel を記述したマニフェストファイルを指定することで、簡単に埋め込みマニフェストとしてリソースに含めることができます。

     

    (2) DllMain の DLL_PROCESS_ATTACH での QueryUserName 関数の呼び出し(GetUserName API の呼び出し)を行わないように実装を変更すれば回避できます(確認済み)。

     

    switch(dwReason) {
        case DLL_PROCESS_ATTACH:
          //QueryUserName(_UserName, USERNAME_SIZE, TRUE); <--- これをやめる
          break;

    }

     

    例えば、DLL に

     

    __declspec(dllexport) void Init()

    {

      QueryUserName(_UserName, USERNAME_SIZE, TRUE);

    }

     

    のような API を用意して、以下のようにアプリケーション側から呼び出すように変更します。

     

    void main(int argc, char *argv[])

    {

      Init();

      TCHAR name[USERNAME_SIZE];

      if (QueryUserName(name, USERNAME_SIZE, TRUE) > 0)

        printf("%s\n", name);

    }

     

     

    上記いずれかの方法で試されてみてはいかがでしょうか。

    2007年3月30日 4:29
  • chack - Akira Inoue さん、確認までしていただきありがとうございます。

     

    DLL は変更できないので、埋め込みマニフェストにより回避するのがよさそうです。

     

    しかし、プログラム名に依存するとはいえ、こんな基本的な API の呼び出しで例外が発生するとなると Windows Vista って大丈夫なのかちょっと不安になります。

     

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

    2007年3月30日 5:30
  •  

    DllMainからAdvapi32.dllのAPI呼ぶなよ
    2008年11月8日 8:35