none
C++のポインタにポインタの変数の値の取得 RRS feed

  • 質問

  • C++2013で電気メーカー提供のdllを呼び出すdllを作成しています.

    電気メーカー提供のdllに以下の関数があり、それを呼び出しています.

    GetValue(DWORd dwGroup,DWORD dwNo,LPOLESTR** lppwszData,LONG* plRet)

    lppwszDataに要素11の配列として値が返ってきます.

    そのため以下のようにコードを記述しました.

    LPOLESTR* v = new LPOLESTR[11];
    hr = GetValue(1,2,(LPOLESTR**)&v, &lRet);

    for (int x = 0; x < 11; x++){
    std::cout <<  *v[x] << std::endl; // 0004
    }

    上記を実行するとたとえばx=5のときは49と出力されました.

    ウォッチウィンドでv[5]を確認するとL”1010”と表示されていましたので、先頭の 1 の ASCIIコードである49が出力されたことがわかります.(添付図参照)

    プログラムで 1010 と出力するにはどうすれば良いでしょうか?何卒ご教授宜しく御願い致します.


    2016年4月28日 4:56

回答

すべての返信

  • LPOLESTR は定義をたどると wchar_t* となっていますので、UNICODE として出力する必要があるかと思います。

    std::wcout << v[x] << std::endl;


    2016年4月28日 5:10
  • 特に置き換えられていない限りWTypesbase.hに以下の様に定義されているので

    typedef WCHAR OLECHAR;
    typedef OLECHAR *LPOLESTR;

    LPOLESTR は wchar_tのポインタです。
    すなわち、v[5]もwchar_tのポインタ、すなわちUnicode文字列として扱えば良いのではないでしょうか。

    2016年4月28日 5:12
  • 一般的に pointer of pointer(この場合 LPOLESTR**)を引数に取る場合、呼び出し先がメモリ確保を行い呼び出し元に返します。挙げられたコードは呼び出し元がメモリ確保を行っていますが、当該APIの仕様を確認することをお勧めします。


    • 編集済み 佐祐理 2016年4月28日 7:21
    2016年4月28日 5:32
  • ご回答ありがとうございます.

    wcoutにて49は1と出力されるようになりました.

    しかし1010とは出力されませんでした.

    2016年4月28日 6:56
  • ご回答ありがとうございます.

    APIの説明書を確認すると

    UNICODE文字列の配列として返します。データ値の配列は、
    本製品側で確保していますので、クライアント側でCoTaskMemFree ()を用いて明
    示的に解放してください

    との記載がありました.

    私が行っている v の宣言には誤りがあるのでしょうか?

    2016年4月28日 6:57
  • ご回答ありがとうございます.

    kenjinote様のアドバイスををもとにwcoutで出力してみましたが1010とは表示されませんでした.

    2016年4月28日 6:59
  • std::wcout << *v[x] << std::endl;

    としていませんか?

    std::wcout << v[i] << std::endl;

    "*" はいりません。

    • 回答としてマーク protecyamyam 2016年4月28日 7:07
    2016年4月28日 7:00
  • 皆様、ご教授ありがとうございました.

    wchar_t* v_u;
    v_u = v[5];

    std::wcout << v_u[5] << std::endl; 

    上記のようにすることで所望の結果を得ることが出来ました.

    初歩的な内容にお手間をお掛けいたしましたが、ありがとうございました.

    2016年4月28日 7:07
  • newに対応するのはdeleteであってCoTaskMemFree()ではありませんから明確に間違っています。

    LPOLESTR* v;
    hr = GetValue(1, 2, &v, &lRet);
    std::wcout << *v << std::endl;
    CoTaskMemFree(v);

    といったところでしょうか。

    2016年4月28日 7:20
  • GetValue の正確な定義が

    GetValue(DWORd dwGroup,DWORD dwNo,LPOLESTR** lppwszData,LONG* plRet);

    と等しい(コンパイル通りませんけどね)として。。

    「UNICODE文字列の配列として返します。データ値の配列は、
    本製品側で確保していますので、クライアント側でCoTaskMemFree ()を用いて明
    示的に解放してください 」

    ということであれば、

    LPOLESTR* v;
    LONG lRet;
    GetValue( 1, 2, &v, &lRet );
    
    for( LONG index = 0 ; index < lRet ; index++ )
    {
      std::wcout << v[index] << std::endl;
    }
    
    CoTaskMemFree( v );
    

    という使い方をするのではないでしょうか?


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    2016年4月28日 7:21
  • LPOLESTRの配列=BSTRの配列なので、配列を解放する前にBSTR自体を解放する必要があるのではないでしょうか。

    LPOLESTR* v;
    LONG lRet;
    GetValue( 1, 2, &v, &lRet );
    
    for( LONG index = 0 ; index < lRet ; index++ )
    {
      std::wcout << v[index] << std::endl;
      SysFreeString(v[index]);
    }
    
    CoTaskMemFree( v );
    

    2016年4月28日 8:32
  • BSTR と、LPOLESTR はC/C++言語的には同じに見えるようにしていますが、実際は異なる文字列型です。

    もし、文字列をBSTRにしているのであれば、LPOLESTR** ではなく、BSTR** にする必要があります。

    今回は、LPOLESTRなので、もし個々の文字列も開放するのなら、SysFreeString ではなく、ループ内で CoTaskMemFree を呼び出すことになります。

    ただ、リファレンスとして提示された文章は、個々の要素の文字列については言及していないので解放しなくていいのでは?と思います。

    このあたりは作成元に聞いてみないとわからないですね。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    2016年4月28日 9:32
  • それだと1文字表示しているだけなので"1010"なんていう文字列が表示されるはずはないと思うのですが、

    質問文に書いたプログラムと実際に動かしていたプログラムが一致していなかったのでは?

    デバッガーの画像とも一致していないですし(変数名が違っている)。


    2016年4月28日 9:52