Direct2D QuickStart - Drawing a Simple Rectangle Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
User avatar
Flipeador
Posts: 1204
Joined: 15 Nov 2014, 21:31
Location: Argentina
Contact:

Direct2D QuickStart - Drawing a Simple Rectangle

Post by Flipeador » 23 Oct 2019, 21:25

Does anyone have any idea why this script works on 32-Bit but not on 64-Bit?:

Code: Select all

; Direct2D QuickStart - Drawing a Simple Rectangle
; https://docs.microsoft.com/en-us/windows/win32/direct2d/getting-started-with-direct2d

#DllLoad D2d1.dll

Gui := GuiCreate(, "Direct2D QuickStart - Drawing a Simple Rectangle")
Gui.Show("w500 h500")
Gui.OnEvent("Close", "ExitApp")

; Create an ID2D1Factory.
ID2D1Factory := BufferAlloc(16)
DllCall("Ole32.dll\CLSIDFromString", "Str", "{06152247-6f50-465a-9245-118bfd3b6007}", "Ptr", ID2D1Factory)
pIFactory := 0
DllCall("D2d1.dll\D2D1CreateFactory", "Int", 0, "Ptr", ID2D1Factory, "Ptr", 0, "UPtrP", pIFactory)

/*
typedef struct D2D1_RENDER_TARGET_PROPERTIES
{
    D2D1_RENDER_TARGET_TYPE type;
    D2D1_PIXEL_FORMAT pixelFormat;
    FLOAT dpiX;
    FLOAT dpiY;
    D2D1_RENDER_TARGET_USAGE usage;
    D2D1_FEATURE_LEVEL minLevel;

} D2D1_RENDER_TARGET_PROPERTIES;
*/
D2D1_RENDER_TARGET_PROPERTIES := BufferAlloc(28)
NumPut("Int"  , 0, D2D1_RENDER_TARGET_PROPERTIES, 0)   ; type
NumPut("Int"  , 0, D2D1_RENDER_TARGET_PROPERTIES, 4)   ; pixelFormat.format
NumPut("Int"  , 0, D2D1_RENDER_TARGET_PROPERTIES, 8)   ; pixelFormat.alphaMode
NumPut("Float", 0, D2D1_RENDER_TARGET_PROPERTIES, 12)  ; dpiX
NumPut("Float", 0, D2D1_RENDER_TARGET_PROPERTIES, 16)  ; dpiY
NumPut("Int"  , 0, D2D1_RENDER_TARGET_PROPERTIES, 20)  ; usage
NumPut("Int"  , 0, D2D1_RENDER_TARGET_PROPERTIES, 24)  ; minLevel

/*
typedef struct D2D1_HWND_RENDER_TARGET_PROPERTIES
{
    HWND hwnd;
    D2D1_SIZE_U pixelSize;
    D2D1_PRESENT_OPTIONS presentOptions;

} D2D1_HWND_RENDER_TARGET_PROPERTIES;
*/
D2D1_HWND_RENDER_TARGET_PROPERTIES := BufferAlloc(2*A_PtrSize+8)
NumPut("Ptr" , Gui.hWnd       , D2D1_HWND_RENDER_TARGET_PROPERTIES, 0)            ; hwnd
NumPut("UInt", Gui.ClientPos.W, D2D1_HWND_RENDER_TARGET_PROPERTIES, A_PtrSize)    ; pixelSize.width
NumPut("UInt", Gui.ClientPos.H, D2D1_HWND_RENDER_TARGET_PROPERTIES, A_PtrSize+4)  ; pixelSize.height
NumPut("Int" , 0              , D2D1_HWND_RENDER_TARGET_PROPERTIES, A_PtrSize+8)  ; presentOptions

; Create an ID2D1HwndRenderTarget.
pRenderTarget := 0
ComCall(2+12, pIFactory, "Ptr", D2D1_RENDER_TARGET_PROPERTIES, "Ptr", D2D1_HWND_RENDER_TARGET_PROPERTIES, "UPtrP", pRenderTarget)

COLORF := BufferAlloc(16)
NumPut("Float", 0xFF, COLORF, 0)   ; R
NumPut("Float", 0x00, COLORF, 4)   ; G
NumPut("Float", 0x00, COLORF, 8)   ; B
NumPut("Float", 0xFF, COLORF, 12)  ; A

; Create a Brush.
pSolidBrush := 0
ComCall(2+1+5, pRenderTarget, "Ptr", COLORF, "Ptr", 0, "UPtrP", pSolidBrush)
;MsgBox "pBrush -> " . pSolidBrush

; Draw the Rectangle.
; BeginDraw
ComCall(2+1+45, pRenderTarget, "Int")  ; Error:  Function returned failure. | Specifically: 0xdc993630
; DrawRectangle
RECTF := BufferAlloc(16)
NumPut("Float", 100, RECTF, 0)   ; left
NumPut("Float", 100, RECTF, 4)   ; top
NumPut("Float", 200, RECTF, 8)   ; right
NumPut("Float", 200, RECTF, 12)  ; bottom
ComCall(2+1+13, pRenderTarget, "Ptr", RECTF, "Ptr", pSolidBrush, "Float", 1, "Ptr", 0, "Int")
; EndDraw
ComCall(2+1+46, pRenderTarget, "UInt64P", 0, "UInt64P", 0)

;MsgBox "Done!"
;ExitApp
The ID2D1RenderTarget::BeginDraw method fails and I don't know why.
AutoHotkey v2.0-a136-feda41f4:

Code: Select all

#Requires AutoHotkey v2.0-a136-feda41f4

; Direct2D QuickStart - Drawing a Simple Rectangle
; https://docs.microsoft.com/en-us/windows/win32/direct2d/getting-started-with-direct2d

#DllLoad D2D1.dll

wnd := Gui(, "Direct2D QuickStart - Drawing a Simple Rectangle")
wnd.Show("w500 h500")
wnd.OnEvent("Escape", ExitApp)
wnd.OnEvent("Close", ExitApp)

; Create an ID2D1Factory.
ID2D1Factory := Buffer(16)
DllCall("Ole32\CLSIDFromString", "Str", "{06152247-6f50-465a-9245-118bfd3b6007}", "Ptr", ID2D1Factory)
DllCall("D2D1\D2D1CreateFactory", "Int", 0, "Ptr", ID2D1Factory, "Ptr", 0, "PtrP", &pIFactory:=0)

/*
typedef struct D2D1_RENDER_TARGET_PROPERTIES
{
    D2D1_RENDER_TARGET_TYPE type;
    D2D1_PIXEL_FORMAT pixelFormat;
    FLOAT dpiX;
    FLOAT dpiY;
    D2D1_RENDER_TARGET_USAGE usage;
    D2D1_FEATURE_LEVEL minLevel;

} D2D1_RENDER_TARGET_PROPERTIES;
*/
D2D1_RENDER_TARGET_PROPERTIES := Buffer(28)
NumPut("Int"  , 0, D2D1_RENDER_TARGET_PROPERTIES, 0)   ; type
NumPut("Int"  , 0, D2D1_RENDER_TARGET_PROPERTIES, 4)   ; pixelFormat.format
NumPut("Int"  , 0, D2D1_RENDER_TARGET_PROPERTIES, 8)   ; pixelFormat.alphaMode
NumPut("Float", 0, D2D1_RENDER_TARGET_PROPERTIES, 12)  ; dpiX
NumPut("Float", 0, D2D1_RENDER_TARGET_PROPERTIES, 16)  ; dpiY
NumPut("Int"  , 0, D2D1_RENDER_TARGET_PROPERTIES, 20)  ; usage
NumPut("Int"  , 0, D2D1_RENDER_TARGET_PROPERTIES, 24)  ; minLevel

/*
typedef struct D2D1_HWND_RENDER_TARGET_PROPERTIES
{
    HWND hwnd;
    D2D1_SIZE_U pixelSize;
    D2D1_PRESENT_OPTIONS presentOptions;

} D2D1_HWND_RENDER_TARGET_PROPERTIES;
*/
wnd.GetClientPos(&cx, &cy, &cw, &ch)
D2D1_HWND_RENDER_TARGET_PROPERTIES := Buffer(2*A_PtrSize+8)
NumPut("Ptr" , wnd.hWnd, D2D1_HWND_RENDER_TARGET_PROPERTIES, 0)            ; hwnd
NumPut("UInt", cw      , D2D1_HWND_RENDER_TARGET_PROPERTIES, A_PtrSize)    ; pixelSize.width
NumPut("UInt", ch      , D2D1_HWND_RENDER_TARGET_PROPERTIES, A_PtrSize+4)  ; pixelSize.height
NumPut("Int" , 0       , D2D1_HWND_RENDER_TARGET_PROPERTIES, A_PtrSize+8)  ; presentOptions

; Create an ID2D1HwndRenderTarget.
ComCall(2+12, pIFactory, "Ptr", D2D1_RENDER_TARGET_PROPERTIES, "Ptr", D2D1_HWND_RENDER_TARGET_PROPERTIES, "PtrP", &pRenderTarget:=0)

COLORF := Buffer(16)
NumPut("Float", 0xFF, COLORF, 0)   ; R
NumPut("Float", 0x00, COLORF, 4)   ; G
NumPut("Float", 0x00, COLORF, 8)   ; B
NumPut("Float", 0xFF, COLORF, 12)  ; A

; Create a Brush.
ComCall(2+1+5, pRenderTarget, "Ptr", COLORF, "Ptr", 0, "PtrP", &pSolidBrush:=0)

; Draw the Rectangle.
; BeginDraw
ComCall(2+1+45, pRenderTarget, "Int")  ; Error:  Function returned failure. | Specifically: 0xdc993630
; DrawRectangle
RECTF := Buffer(16)
NumPut("Float", 100, RECTF, 0)   ; left
NumPut("Float", 100, RECTF, 4)   ; top
NumPut("Float", 200, RECTF, 8)   ; right
NumPut("Float", 200, RECTF, 12)  ; bottom
ComCall(2+1+13, pRenderTarget, "Ptr", RECTF, "Ptr", pSolidBrush, "Float", 1, "Ptr", 0, "Int")
; EndDraw
ComCall(2+1+46, pRenderTarget, "UInt64P", 0, "UInt64P", 0)

Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Direct2D QuickStart - Drawing a Simple Rectangle

Post by Helgef » 24 Oct 2019, 01:08

I see the same result on both 32 and 64, a red rectangle. no errors.

User avatar
Flipeador
Posts: 1204
Joined: 15 Nov 2014, 21:31
Location: Argentina
Contact:

Re: Direct2D QuickStart - Drawing a Simple Rectangle

Post by Flipeador » 24 Oct 2019, 05:24

I restarted the system and now it seems to work correctly. That error was really weird.
Thank you!

swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Direct2D QuickStart - Drawing a Simple Rectangle  Topic is solved

Post by swagfag » 07 Jun 2021, 08:02

Flipeador wrote:
24 Oct 2019, 05:24
I restarted the system and now it seems to work correctly. That error was really weird.
not weird and likely not working correctly(at least certainly not all the time)
from d2d1.h ID2D1RenderTarget's vtable wrote:

Code: Select all

    /// <summary>
    /// Start drawing on this render target. Draw calls can only be issued between a
    /// BeginDraw and EndDraw call.
    /// </summary>
    STDMETHOD_(void, BeginDraw)(
        ) PURE;
thats void return type. ComCall says(too lazy to check what it used to say back when this sample was written, but it was probably something in a similar vein):
ComCall's return type wrote:If omitted, the return type defaults to HRESULT, which is most the common return type for COM interface methods. Any result indicating failure causes an OSError to be thrown; therefore, the return type must not be omitted unless the actual return type is HRESULT.

If the method is of a type that does not return a value (the void return type in C), specify "Int" or any other numeric type without any suffix (except HRESULT), and ignore the return value. As the content of the return value register is arbitrary in such cases, an exception may or may not be thrown if ReturnType is omitted.
so,

Code: Select all

; BeginDraw
ComCall(2+1+45, pRenderTarget, 'Int')
and the same goes for other methods(not all return HRESULTs, and not all are void either. u have to actually check and set it accordingly)

User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: Direct2D QuickStart - Drawing a Simple Rectangle

Post by kczx3 » 07 Jun 2021, 09:32

@swagfag I reckon you edited the OP to have the sample for v2-a136. Did you intend to simply translate the code by @Flipeador or did you intend to include your recommended fix for the BeginDraw and EndDraw calls?

swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Direct2D QuickStart - Drawing a Simple Rectangle

Post by swagfag » 07 Jun 2021, 10:07

i dont understand what ure asking me. i havent edited anything nor can i edit an OP im not the submitter of. the fix for BeginDraw(and possibly other similarly broken methods if there are any, i havent checked) is to double-check their return types and specify them in the ComCall call according to ComCall's documentation excerpt

User avatar
Flipeador
Posts: 1204
Joined: 15 Nov 2014, 21:31
Location: Argentina
Contact:

Re: Direct2D QuickStart - Drawing a Simple Rectangle

Post by Flipeador » 07 Jun 2021, 10:23

@swagfag Thank you!. Pretty sure that was the problem. I haven't touched the code since then. :thumbup:
@kczx3 I have edited it before I saw swagfag's answer.

:wave:

User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: Direct2D QuickStart - Drawing a Simple Rectangle

Post by kczx3 » 07 Jun 2021, 10:54

@swagfag Apologies! I sort of assumed you were the one to put the updated code in the OP (skipped my mind that you're not a moderator here!). And Flipeador hasn't been active in quite some time so never occurred to me that it was updated by him.

Sorry again :)

iseahound
Posts: 1445
Joined: 13 Aug 2016, 21:04
Contact:

Re: Direct2D QuickStart - Drawing a Simple Rectangle

Post by iseahound » 07 Jun 2021, 11:47

Could someone explain why it is necessary to specify int as the return value? I understand that the function assumes an HRESULT if the return value is omitted, but the type of HRESULT is just int, so if it is already assuming an integer return value why specify int again? Sorry if this is a silly question.

User avatar
Onimuru
Posts: 107
Joined: 08 Sep 2018, 18:35
Contact:

Re: Direct2D QuickStart - Drawing a Simple Rectangle

Post by Onimuru » 07 Jun 2021, 13:31

Because if the return type is HRESULT, any return value other than 0 will throw an OSError which in turn closes the script.

swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Direct2D QuickStart - Drawing a Simple Rectangle

Post by swagfag » 07 Jun 2021, 16:01

iseahound wrote:
07 Jun 2021, 11:47
the function assumes an HRESULT if the return value is omitted, but the type of HRESULT is just int, so if it is already assuming an integer return value why specify int again?
correct, and it is additionally because of the fact that this returned Int is then meant to be interpreted as an HRESULT(as @Onimuru writes, if that's the case, any non-0 result will throw)
ComCall is just DllCall with some types/args/return types predefined and rearranged, and:
DllCall wrote:DllCall returns the actual value returned by Function. If Function is of a type that does not return a value, the result is an undefined value of the specified return type (integer by default).
  • for DllCall, ure meant to ignore that value(or do whatever with it, but that would be meaningless).
  • for ComCall, if u omit the return type(or actually set it to HRESULT explicitly), u can no longer ignore the return value - instead, the script will throw if a non-0 was returned(which is probably why the script worked for @Flipeador occasionally, ie when 0 was being returned, which is S_OK in HRESULT speak)
i guess u could also not specify the Int(void) return type and have the call wrapped in a try instead to suppress any would-be errors, but whether thats possible would depend on surrounding code, so not an actual solution

Post Reply

Return to “Ask for Help (v2)”