miyuriの日記: C++とCOMの分からないところ 4
【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で使いたい場合、ふつーにキャストして呼べば、いけそうな気がするする。
ふつーにキャストして呼べば (スコア:0)
こんな感じ?
typedef D2D1_SIZE_F *(__stdcall *GetBitmapSizeFunc)(ID2D1Bitmap *bitmap, D2D1_SIZE_F *output);
((GetBitmapSizeFunc) d2d1.bitmap->lpVTbl->GetSize)(bitmap, &sizeok);
これが逆(Cのcallerはポインタ経由で返されることを期待しているのにC++のcalleeはレジスタに返す)だったらインラインアセンブラでも書かない限りお手上げだっただろうけど。
Re: (スコア:0)
件のスレのID:sPDu10Ezですが、キャストでいけました。
しかし、MSDNを調べても構造体の返し方についての記述が見つからなくて
結局仕様なのかバグなのかわからなかったんですがどうなんでしょうねこれ。
Re:ふつーにキャストして呼べば (スコア:1)
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 .
}
extern "C" 宣言で、 (スコア:0)
なんとかならんかな?