Direct2D COM calls returning 64-bit structs and C++Builder 2010

136 Views Asked by At

I'm trying to get the size of a Direct2D Bitmap and getting an immediate crash.

// props and target etc all set up beforehand.
CComPtr<ID2D1Bitmap> &b;
target->CreateBitmap(D2D1::SizeU(1024,1024), frame.p_data, 1024* 4, &props, &b));

D2D_SIZE_U sz = b->GetPixelSize();  // Crashes here.

All other operations using the bitmap (including drawing it) work correctly. It's just returning the size that seems to be the problem.

Based on a articles like this by Rudy V, my suspicion is that it's some incompatibility with C++Builder 2010 and how COM functions return 64-bit structures. http://rvelthuis.de/articles/articles-convert.html

The Delphi declaration of GetPixelSize looks like this: (from D2D1.pas)

// Returns the size of the bitmap in resolution dependent units, (pixels).
procedure GetPixelSize(out pixelSize: TD2D1SizeU); stdcall; 

... and in D2D1.h it's

//
// Returns the size of the bitmap in resolution dependent units, (pixels).
//
STDMETHOD_(D2D1_SIZE_U, GetPixelSize)(
    ) CONST PURE;

Can I fix this without rewriting the D2D headers?

All suggestions welcome - except upgrading from C++Builder 2010 which is more of a task than I'm ready for at the moment.

1

There are 1 best solutions below

0
Wolfgang Sauer On

„getInfo“ is a function derived from Delphi code, which can work around.

void getInfo(void* itfc, void* info, int vmtofs)
{
    asm {
        push info           // pass pointer to return result
        mov eax,itfc        // eax poionts to interface
        push eax            // pass pointer to interface
        mov eax,[eax]       // eax points to VMT
        add eax,vmtofs      // eax points rto address of virtual function
        call dword ptr [eax]    // call function
    }
}

Disassembly of code generated by CBuilder, which results in a crash:

Graphics.cpp.162: size = bmp->GetSize();
00401C10 8B4508           mov eax,[ebp+$08]
00401C13 FF7004           push dword ptr [eax+$04]
00401C16 8D55DC           lea edx,[ebp-$24]
00401C19 52               push edx
00401C1A 8B4D08           mov ecx,[ebp+$08]
00401C1D 8B4104           mov eax,[ecx+$04]
00401C20 8B10             mov edx,[eax]
00401C22 FF5210           call dword ptr [edx+$10]
00401C25 8B4DDC           mov ecx,[ebp-$24]
00401C28 894DF8           mov [ebp-$08],ecx
00401C2B 8B4DE0           mov ecx,[ebp-$20]
00401C2E 894DFC           mov [ebp-$04],ecx

„bmp“ is declared as

ID2D1Bitmap* bmp;

Code to call „getInfo“:

D2D1_SIZE_F size;
getInfo(bmp,&pf,0x10);

You get 0x10 (vmtofs) from disassembly line „call dword ptr [edx+$10]“

You can call „GetPixelSize“, „GetPixelFormat“ and others by calling „getInfo“

D2D1_SIZE_U ps;// = bmp->GetPixelSize();
getInfo(bmp,&ps,0x14);
D2D1_PIXEL_FORMAT pf;// = bmp->GetPixelFormat();
getInfo(bmp,&pf,0x18);

„getInfo“ works with methods „STDMETHOD_ ... CONST PURE;“, which return a result.

STDMETHOD_(D2D1_SIZE_F, GetSize)(
    ) CONST PURE;

For this method CBuilder generates malfunctional code.

In case of

STDMETHOD_(void, GetDpi)(
    __out FLOAT *dpiX,
    __out FLOAT *dpiY 
    ) CONST PURE;

the CBuilder code works fine, „getDpi“ results void.