[SOLVED] Issues with GDI+ GdipEffectCreate

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Eidola
Posts: 22
Joined: 25 Aug 2016, 14:44

[SOLVED] Issues with GDI+ GdipEffectCreate

26 Sep 2016, 06:48

So, I was going to wait until I was closer to being finished to announce the project I have been working on... but since I have ran into a rather strange issue trying to implement effects I guess the cat is out of the bag now! ;)

I am writing a fully object-oriented rewrite of tic (and friends) GDI+ flat API for AutoHotkey! It is more or less modeled after the C++ wrapper, though I did not directly set out to do that, it has just worked out that way so far. To demonstrate it I will also have a user interface layer that can be used with full support for alpha-blended layered windows. I will have some things I can demonstrate in the very near future, and may even want some beta-testers to help make sure it all works well. Also, the code is heavily commented! :)

Now, the issue I am having is with this very simple code shown below:

Code: Select all

#include GDIplus.ahk		; tic's version, not my new one

pToken := Gdip_Startup() 

GUID := "{633c80a4-1843-482b-9ef2-be2834c5fdd4}"

VarSetCapacity(CLSID, 16,0)
DllCall("ole32\CLSIDFromString", WStr, GUID, Ptr, &CLSID)

retVal := DllCall("gdiplus\GdipCreateEffect", Ptr, &CLSID, PtrP, hEffect) 

OutputDebug, status[%retVal%] effect[%hEffect%] error[%A_LastError%]      

Gdip_Shutdown(pToken)
Under the latest U64 build of AutoHotkey this bit of code works great, hEffect contains a handle to a GDI+ effect object. Under the latest U32/A32 versions of AutoHotkey the script crashes with an access violation exception. I installed Visual Studio 2015 and let it run the JIT debugger and it said the access violation was from trying to access memory location 0x00000017, so yea, bad. ;)

I then compiled a new U32 version of AutoHotkey using VS2015, and while the newly compiled version no longer gives me an access violation, instead this test script just gives me a Win32 error status code... well, at least it isn't an access violation. What I don't get is that the exact same call to GdipCreateEffect in the __New method of my base Effect class doesn't... there I get an A-12 DllCall error, meaning it thinks I am missing 12 bytes of parameters to the GdipCreateEffect call? I am not sure why in the test script above I get a Win32 error from GDI+ and the exact same call gives me an A-12 error from AHK in my actual code... some stack cleanup issue perhaps? Sigh. :headwall:

So, why will this code work on U64 but not on U32/A32... has anyone else had luck getting GDI+ effects to work under 32-bit builds? Yes, I know the effects are a GDI+ v1.1 bit of code only, that is not an issue. However, I would really like to make my GDI+ library work on A32, U32, and U64 versions of AutoHotkey v1.1+ if at all possible!
Last edited by Eidola on 26 Sep 2016, 22:35, edited 2 times in total.
Eidola
Posts: 22
Joined: 25 Aug 2016, 14:44

Re: Issues with GDI+ GdpiEffectCreate

26 Sep 2016, 06:56

Okay, so a small update... I commented out one of my classes where I hook window events via shell hook and the A-12 error went away and become the GDI+ Win32 error.

So, do I somehow have some stack corruption happening somewhere as well to track down? :(

EDIT: Well, this is strange... so I went through the code I disabled and discovered the A-12 error went away when I commented out the line of code that called RegisterShellHookWindow. The strange thing is I reverted all the changes via Subversion I made while tracking down the issue and the A-12 error didn't come back, just the GDI+ Win32 error code still. :wtf: EDIT2: Spoke too soon, when I reverted changes I was down one directory and missed a file, the A-12 error still exists!
Well, the good news is that now I only have one error to worry about, the Win32 error being returned by GDI+ when trying to create an effect object... still works under U64, but not U32 or A32. I am trying to make a test-case that demonstrates the A-12 error, but so far I've created skeletons of most of the involved classes and no A-12 error... other than not having enough parameters can anything else cause this error?

BTW, how do I compile an A32 version of AutoHotkey in Visual Studio?

Just to note, that other than the drawing commands on the graphics surface I probably have about 75% of the original GDIplus.ahk file implemented as objects now. Everything is managed, you don't ever have to dispose or delete anything yourself, just create, use, and forget! I do still have a fair bit of work to go, but will make a post detailing the new library I am creating soon! :)
Eidola
Posts: 22
Joined: 25 Aug 2016, 14:44

Re: Issues with GDI+ GdipEffectCreate

26 Sep 2016, 10:36

Okay, I have figured out the source of the A-12 error... the try-catch block I use during initialisation of my whole system to check for errors... derp. So I guess when GdipCreateEffect throws the Win32 error then DllCall is throwing an exception with more detail should there be a try statement listening for one?
[v1.1.04+] This function is able to throw an exception on failure. For more information, see Runtime Errors.
Okay, so I guess what I thought was two errors is actually just one error being reported two different ways... phew, at least I have that figured out... at least, I hope that's what is going on! ;) EDIT: As the quote above indicates, and I'm surprised Lexikos didn't post and quote himself, yes, that is the case DllCall will throw exceptions on errors! :)

So, why does the 32-bit version of AHK think I am 12-bytes short sending a GUID to GdipCreateEffect? If I am 12 bytes short in the 32-bit version shouldn't I still be short some bytes in the 64-bit version?

Well, I am off to bed to get some sleep... today has not been a very productive day for my little project. Too much banging my head against a wall, and sadly there is so very little documentation online for GDI+, which really doesn't help! :headwall:

Ah well, thanks to anyone who can shed some light on this issue... I will keep developing using the 64-bit version of AHK for now, will just disable testing Effects on the 32-bit version until I can get a fix of some sort.

Also, may need some help with creating a Message Hook DLL for creating a global hook for the message queues of arbitrary windows... but I can create a separate thread for that later! :)
Last edited by Eidola on 26 Sep 2016, 22:44, edited 4 times in total.
Eidola
Posts: 22
Joined: 25 Aug 2016, 14:44

Re: Issues with GDI+ GdipEffectCreate

26 Sep 2016, 19:31

One thought... a GUID is 128-bits, which is 16 bytes. In 32-bit land a pointer is 4 bytes, leaving 12 bytes remaining... the same size AutoHotkey is saying I am missing. Can you pass 16-byte values directly to functions? I thought everything on the stack had to work in pointer sizes? So 4 bytes for 32-bit and 8 bytes for 64-bit?

Looking at the definition of the GUID type in Visual Studio I see:

Code: Select all

typedef struct _GUID {
    unsigned long  Data1;
    unsigned short Data2;
    unsigned short Data3;
    unsigned char  Data4[ 8 ];
} GUID
;

No pointer variants of the struct name are present, like *LPGUID or anything... okay and the definition for GdipCreateEffect is:

EDIT: Okay, I found the extra definitions for *LPGUID and *LPCGUID, but those typedef's aren't being used for GdipCreateEffect, so still wondering how this is all supposed to be working! ;)

Code: Select all

Status __stdcall
GdipCreateEffect(const GUID guid, CGpEffect **effect);
Again, no specification that GUID is being passed as a pointer... so is the actual full 16 byte GUID being passed straight to this function via the stack somehow? I am just tossing out ideas here trying to figure out why this won't work in 32-bit land... obviously a pointer to the structure containing the GUID must be passed somehow as that is what the code is doing, and it works in 64-bit land.

I did a search and found that AutoIt apparently had a hard crash trying to call GdipCreateEffect as well, though it was reversed, the crash there was on 64-bit not 32-bit. Here is a thread discussing the issue there: https://www.autoitscript.com/forum/topi ... plus-call/

I am already using the Struct library by HotKeyIt! and have tried creating a struct to hold the GUID and passing a pointer, but that really is just essentially the same as doing it with VarSetCapacity and passing a pointer... so that was a dead end.

Does anyone have any idea what the issue is with the 32-bit version of AutoHotkey and this GUID parameter to GdipCreateEffect?
Eidola
Posts: 22
Joined: 25 Aug 2016, 14:44

Re: Issues with GDI+ GdipEffectCreate

26 Sep 2016, 22:35

Well, I have solved the issue! :superhappy: :dance: :bravo:

The following code works on A32, U32 and U64:

Code: Select all

#include Legacy/AHK/GDIplus.ahk     ; tic's version, not my new one                                                                 
                                                                                                                                    
pToken := Gdip_Startup()                                                                                                            
                                                                                                                                    
GUID := "{633c80a4-1843-482b-9ef2-be2834c5fdd4}"                                                                                    
                                                                                                                                    
VarSetCapacity(CLSID, 16,0)                                                                                                         
DllCall("ole32\CLSIDFromString", WStr, GUID, Ptr, &CLSID)                                                                           
                                                                                                                                    
if (A_PtrSize == 4)     ; x86: Pass GUID as two 64-bit parameters                                                                   
    retVal := DllCall("gdiplus\GdipCreateEffect", Int64, NumGet(CLSID, 0, "Int64"), Int64, NumGet(CLSID, 8, "Int64"), PtrP, hEffect)
else                    ; x64: Pass GUID as a pointer(!?)                                                                           
    retVal := DllCall("gdiplus\GdipCreateEffect", Ptr, &CLSID, PtrP, hEffect)                                                       
                                                                                                                                    
OutputDebug, status[%retVal%] effect[%hEffect%] error[%A_LastError%]                                                      
                                                                                                                                    
Gdip_Shutdown(pToken)                                                                                                               
After poking around the AutohotKey source code for a bit and reading about the issue AutoIt had I realised that it does indeed seem that the GUID is being passed directly to the GdipCreateEffect function, instead of via a pointer... well, at least in 32-bit land.

For the 32-bit call I simply pass two 64-bit params, one with each half of the GUID, then the pointer to hold the effect handle and everything works... I didn't even think passing extra params would be possible, until I realised that the number of params is actually just the function popping things off the stack AutoHotkey creates before calling it! So, this works exactly as I thought, 128-bit (16-byte) GUID parameter is on the stack for the 32-bit call and everything works.

What I do not yet understand is why the 64-bit version will happily take a pointer to the GUID, instead of the actual GUID like the 32-bit version required? I wonder if there isn't something different between the 64-bit and 32-bit versions of GdipCreateEffect perhaps?

Well at least the issue has been resolved and now I can create GDI+ effect objects in all three versions of AutoHotkey... hmm, just realised I haven't tested this code with the officially released versions yet, just my recompiled (with no source changes though) versions. EDIT: Yes, the above code does work with all three official versions, A32, U32, and U64!

Anyways, now the cat is out of the bag, I will try to get a post made about my GDI+ flat API wrapper for AutoHotkey soon... I just want to get a few more things implemented first. 8-)
User avatar
noname
Posts: 515
Joined: 19 Nov 2013, 09:15

Re: [SOLVED] Issues with GDI+ GdipEffectCreate

27 Sep 2016, 07:52

Thanks in advance for your work , looking forward to see it :)
Also, the code is heavily commented!
Much appreciated !I hope it will collect a lot of examples from forum members to help using it.
Eidola
Posts: 22
Joined: 25 Aug 2016, 14:44

Re: [SOLVED] Issues with GDI+ GdipEffectCreate

28 Sep 2016, 08:56

I plan to release the library with a basic UI engine as well, including support for layered windows as a bit of a demonstration platform. I have created a text file with a list of all the GDI+ Flat API calls and I am now working my way through implementing as many of them as I think will be needed for v1 of my library! :)

Actually, I just got a layered window to fade in while also going from a Gaussian blur of 30 down to 0 and from an alpha of 0 to 1... though that really only works well for small windows, get the window up in size and it is slow... but it was fun to see it work... oh yea, and the whole window was sepia-toned as well.. all on-the-fly! :D

Right now my little UI engine is a fully layer backed style system. Each control has a backing layer it renders into, but only if dirty, so if the control hasn't changed and the parent needs a redraw then it just quickly draws the already existing backing layer, otherwise it will re-render the control into the backing layer to update it... so far it works quite well!

I will post more, probably on a new thread sometime in the next week... or two... depends on how my progress goes with creating all these API call and testing things... hmm, I really should figure out a testing harness for this project soon as well! ;)
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: Issues with GDI+ GdipEffectCreate

15 Sep 2023, 05:01

Eidola wrote:
26 Sep 2016, 22:35
Well, I have solved the issue! :superhappy: :dance: :bravo:

Code: Select all

if (A_PtrSize == 4)     ; x86: Pass GUID as two 64-bit parameters                                                                   
    retVal := DllCall("gdiplus\GdipCreateEffect", Int64, NumGet(CLSID, 0, "Int64"), Int64, NumGet(CLSID, 8, "Int64"), PtrP, hEffect)
else                    ; x64: Pass GUID as a pointer(!?)                                                                           
    retVal := DllCall("gdiplus\GdipCreateEffect", Ptr, &CLSID, PtrP, hEffect)                                                       
 
I am writing my own graphics lib (for v2.0) and got stuck with this issue for a few minutes.. I searched forum without hopes... and Oh my! :shock:
Thanks @Eidola :thumbup:
 
@lexikos Please confirm if this is safe to use in v2.0.
iseahound
Posts: 1448
Joined: 13 Aug 2016, 21:04
Contact:

Re: [SOLVED] Issues with GDI+ GdipEffectCreate

15 Sep 2023, 08:14

Don't use this API. GdipEffectCreate has been abandoned by Microsoft and has bugs that will never be fixed.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: [SOLVED] Issues with GDI+ GdipEffectCreate

15 Sep 2023, 11:19

iseahound wrote:
15 Sep 2023, 08:14
Don't use this API. GdipEffectCreate has been abandoned by Microsoft and has bugs that will never be fixed.
Oh! Any links to understand this more?
lexikos
Posts: 9593
Joined: 30 Sep 2013, 04:07
Contact:

Re: [SOLVED] Issues with GDI+ GdipEffectCreate

15 Sep 2023, 17:56

Yes, assuming the function takes a GUID by value. In general, this is how you pass a struct by value in current versions. v2.1 allows defining the GUID struct and specifying that as the parameter type instead (but it is still in alpha).
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: [SOLVED] Issues with GDI+ GdipEffectCreate

15 Sep 2023, 22:38

lexikos wrote:
15 Sep 2023, 17:56
Yes, assuming the function takes a GUID by value. In general, this is how you pass a struct by value in current versions. v2.1 allows defining the GUID struct and specifying that as the parameter type instead (but it is still in alpha).
 
Thanks @lexikos :thumbup:

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Descolada, hiahkforum, yxldh and 169 guests