パスワードを忘れた? アカウント作成
11713224 journal
日記

miyuriの日記: C++とCOMの分からないところ 4

日記 by miyuri

【C++】 DirectX初心者質問スレ Part38 【C】
http://peace.2ch.net/test/read.cgi/tech/1370015791/

903 名前:デフォルトの名無しさん[sage] 投稿日:2014/11/15(土) 10:25:57.12 ID:wqk8JEIV
Direct2DってC言語での動作は保証とかされてない感じですか
C言語マクロのID2D1Bitmap_GetSize(hoge)を使ったりlpVtblからのGetSize呼び出しでも
ランライムチェックでESPレジスタの値がおかしいとかメッセージが出て止まります

ID2D1Bitmapだと他にGetPixelSize()もGetPixelFormat()もアウトなんで
たぶん戻り値が構造体になっている関数がアウトなんだと思うんですが、賢い回避策とかありますかね

906 名前:デフォルトの名無しさん[sage] 投稿日:2014/11/15(土) 20:35:48.31 ID:wqk8JEIV
32/64を間違ってるとはどういうことですか
プロジェクトプロパティのライブラリディレクトリは↓になっていて
ソース中に#pragma comment(lib, "d2d1.lib")と書いてリンクしてます
Win32時 $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);
x64時  $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);

↓のD2D1_Initという関数の90行目以下が問題の部分
http://codepad.org/GDr40N4L

妙に気になったので、調べてみたけど、良くわからない。
/(^o^)\

ID2D1Bitmap::GetSize とかは何故か ret 8 するから、esp が期待する値より4大きくなる。
C++だと、何故か this よりも先にスタックに作業領域らしきモノのアドレスを積むので、期待通りの動作をする。
Microsoft Visual C++ 2013 のコンパイラを使用、とりあえずx86。

//append:
その後、こう続いた。

907 名前:デフォルトの名無しさん[sage] 投稿日:2014/11/16(日) 03:10:36.47 ID:sPDu10Ez
C++で呼び出してる時はGetSizeの第二引数に返値の構造体のアドレスをpushして
返値はeaxにそのアドレスがセットされる前提のコードが生成されてるけど
Cで呼び出すと第一引数のID2D1Bitmapのインスタンスだけpushして
返値はedx:eaxに返値の構造体の中身が入ってるコードになってる

両方callee側でスタックを戻す前提になってるから__stdcallで宣言されてるはずだが

909 名前:デフォルトの名無しさん[sage] 投稿日:2014/11/16(日) 07:45:35.02 ID:sPDu10Ez
>>903
呼び出し規約の設計ミス or コンパイラのバグっぽい
グローバルの__stdcall関数とクラスメンバの__stdcall関数で構造体の返し方が違う
後者で実装されているID2D1Bitmap::GetSize()を前者の方法で呼び出してるので
スタックが不整合を起こす
Cで後者の呼び出し規約を使う手段はないだろうからお手上げ

バイナリ互換が失われるからコンパイラのバグだったとしても
修正されることもないだろうしなー

Cで使いたい場合、ふつーにキャストして呼べば、いけそうな気がするする。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • by Anonymous Coward on 2014年11月16日 10時00分 (#2711861)

    こんな感じ?
    typedef D2D1_SIZE_F *(__stdcall *GetBitmapSizeFunc)(ID2D1Bitmap *bitmap, D2D1_SIZE_F *output);
    ((GetBitmapSizeFunc) d2d1.bitmap->lpVTbl->GetSize)(bitmap, &sizeok);
    これが逆(Cのcallerはポインタ経由で返されることを期待しているのにC++のcalleeはレジスタに返す)だったらインラインアセンブラでも書かない限りお手上げだっただろうけど。

    • by Anonymous Coward

      件のスレのID:sPDu10Ezですが、キャストでいけました。

      しかし、MSDNを調べても構造体の返し方についての記述が見つからなくて
      結局仕様なのかバグなのかわからなかったんですがどうなんでしょうねこれ。

      • wine のそれっぽい所のソースコード(http://source.winehq.org/git/wine.git/blob/HEAD:/dlls/d2d1/render_target.c)でも、
        static D2D1_SIZE_F * STDMETHODCALLTYPE d2d_d3d_render_target_GetSize(ID2D1RenderTarget *iface, D2D1_SIZE_F *size)
        という感じで定義されていますね。
        # だからどうというわけではないけど。

        --
        svn-init() {
          svnadmin create .svnrepo
          svn checkout file://$PWD/.svnrepo .
        }
        親コメント
  • by Anonymous Coward on 2014年11月16日 13時32分 (#2711908)

    なんとかならんかな?

typodupeerror

私はプログラマです。1040 formに私の職業としてそう書いています -- Ken Thompson

読み込み中...