Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate

Allowing Function Pointer in DllCall


  • Please log in to reply
43 replies to this topic
Sean
  • Guests
  • Last active:
  • Joined: --
I'm not an AutoHotkey user, however, I'm curious why AHK hasn't this feature yet. I think it's just a few lines of codes addtion to already existing codes, and AHK will have some benefits from it, like COM ability through VTable method. Here is an example: changing Wallpaper via IActiveDesktop (:need XP or higher, I think). Actually, others, like WMI etc, also can be done by this method of course, although a bit cumbersome compared to the dispatch method. It'll need msjava.dll for calling function pointer, which can be easily obtained from the web if missing in the system.

sFile := "C:\WINDOWS\Web\Wallpaper\Home.jpg"

VarSetCapacity(wFile, 260 * 2)
VarSetCapacity(CLSID_ActiveDesktop, 16)
VarSetCapacity( IID_IActiveDesktop, 16)

EncodeInteger(&CLSID_ActiveDesktop     , 0x75048700)
EncodeInteger(&CLSID_ActiveDesktop +  4, 0xEF1F | 0x11D0 << 16)
EncodeInteger(&CLSID_ActiveDesktop +  8, 0x98 | 0x88 << 8 | 0x00 << 16 | 0x60 << 24)
EncodeInteger(&CLSID_ActiveDesktop + 12, 0x97 | 0xDE << 8 | 0xAC << 16 | 0xF9 << 24)

EncodeInteger(&IID_IActiveDesktop     , 0xF490EB00)
EncodeInteger(&IID_IActiveDesktop +  4, 0x1240 | 0x11D1 << 16)
EncodeInteger(&IID_IActiveDesktop +  8, 0x98 | 0x88 << 8 | 0x00 << 16 | 0x60 << 24)
EncodeInteger(&IID_IActiveDesktop + 12, 0x97 | 0xDE << 8 | 0xAC << 16 | 0xF9 << 24)

DllCall("MultiByteToWideChar", "Uint", 0, "Uint", 0, "Uint", &sFile, "int", -1, "Uint", &wFile, "int", 260)

DllCall("ole32\CoInitialize", "Uint", 0)

DllCall("ole32\CoCreateInstance", "Uint", &CLSID_ActiveDesktop, "Uint", 0, "Uint", 1, "Uint", &IID_IActiveDesktop, "UintP", ppv)

pv := DecodeInteger(ppv)

DllCall("msjava\call", "Uint", DecodeInteger(pv + 4*5), "Uint", ppv, "Uint", &wFile, "Uint", 0)
DllCall("msjava\call", "Uint", DecodeInteger(pv + 4*3), "Uint", ppv, "Uint", 7)
DllCall("msjava\call", "Uint", DecodeInteger(pv + 4*2), "Uint", ppv)

DllCall("ole32\CoUninitialize")

DecodeInteger(ptr)
{
  DllCall("RtlMoveMemory", "UintP", deref, "Uint", ptr, "Uint", 4)
  Return deref
}

EncodeInteger(ref, val)
{
  DllCall("ntdll\RtlFillMemoryUlong", "Uint", ref, "Uint", 4, "Uint", val)
}


majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
There was already a big discussion about this.
I beleive that adding such functionality to AHK would bring it to another level, but many others don't think it is so important including Chris, unless he changed his mind in the meantime. This will probably be implemented one day but IF and WHEN, we are about to see...

Its good place, here, again, to reference this library for foreign function calls that could be integrated into AHK - C/Invoke
Posted Image

Sean
  • Guests
  • Last active:
  • Joined: --
What I was asking is a lot simpler one, and I thought AHK almost got there already. Essentially only one additional check whether the first argument is an integer or a string "dll\ftn", then jump to the appropriate place. So, if implemented the codes would look like

DllCall(DecodeInteger(pv + 4*5), "Uint", ppv, "Uint", &wFile, "Uint", 0)
DllCall(DecodeInteger(pv + 4*3), "Uint", ppv, "Uint", 7)
DllCall(DecodeInteger(pv + 4*2), "Uint", ppv) 



PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005

many others don't think it is so important including Chris

Seems to be a slightly biased way of reporting the discussions...
I don't recall Chris discarding callbacks as unimportant, but as hard to implement properly.
This might have not the highest priority indeed, so perhaps he didn't had time to do the right researches, but if somebody presented him usable code, he would be able to integrate it sooner.

To Sean, what you present is interesting, but I must admit I don't understand it. Although I am familiar with Windows API, I never had time to study properly Com and related, so your code is quite cryptic for me. Alas, Chris is, AFAIK, at the same state than me, that's what prevented him to add Com support to AHK up to now.
We reckon the usefulness of a full Com support in AutoHotkey, but it won't come soon, I fear.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
I would like to see COM support and callbacks implemented, but I don't fully understand them. Like many things, maybe they just seem daunting, becoming easier after you learn them.

The project could really use another developer who has an interest in these areas.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006

Seems to be a slightly biased way of reporting the discussions...

Not at all.
As you just said, you and Chris don't think it would be benefitial. Its hard for me to grasp such .... hm.... vision ..... as COM is primarly made for automatition, and AHK is automatition language. Being automatition language and not supporting the system native way of automatition while trying to automate the very same system, is really a problem.

Anyway, I was not talking about COM, but FFI.

I see now that I missunderstood the topic.... Sean wants AHK functions as first class values.
Posted Image

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005

As you just said, you and Chris don't think it would be benefitial.

:?: Where do you see that!?
Personally, I think exactly the reverse, ie. callbacks would be a great addition to DllCall, allowing the use of some API functions currently unusable.

Anyway, I was not talking about COM, but FFI.

Yes, but Sean was talking about Com.

I see now that I missunderstood the topic.... Sean wants AHK functions as first class values.

That's not what I understood, but I can get wrong here. From what I grasped, he wants a facility to provide a pointer on an API function to another API function.

Sean, please, can you confirm my explanation?
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

Sean
  • Guests
  • Last active:
  • Joined: --
I'm afraid I caused a confusion because I wasn't clear enough. What I asked was simple: let allow using function pointers in place of function names in DllCall(). Then, the places in which it could be used most beneficially would be COM. There could be other cases like calling APIs exported with ordinal only without name, however, the chances of finding useful ones of the kind may be rare as usually they are not documented. Here is one example of the kind which will invoke the run... dialog (need msjava.dll again currently):

hModule := DllCall("LoadLibrary", "str", "shell32.dll")
pRunDlg := DllCall("GetProcAddress", "Uint", hModule, "Uint", 61)

DllCall("msjava\call", "Uint", pRunDlg, "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0)
; DllCall(pRunDlg, "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0)
; if the feature is implemented

DllCall("FreeLibrary", "Uint", hModule)


I'm not by any means an expert on COM either. But, I'd like to stress that the VB-like fancy way is not the only way to invoke COM, there is another way to achieve it, namely C/C++ like way. As a matter of fact, C/C++ way is more broader than VB way in scope. For example, my example here with IActiveDesktop can't be invoked from a VBScript.

Although I don't think it's quite correct conceptually, in practice from the point of view of C/C++, COM object could be usefully viewed as a Class in C++, I think (:btw, I'm not an expert on C/C++). So, what I did in the first example can be regraded as calling the member functions by their offsets in its VTable.

I'm not saying there is no need to implement VBScript way to do COM. On the contrary, I think it should be, as majority of the scripters expect this way when talking about COM (:btw, my friend told me LuaCom can be a valuable source in this regard). Until it's implemented fully, however, C/C++ way can be an execellent work-around. And a good news for the developers is that it doesn't require anything more on the developers side, only require a lot of reseach on users side.

If it's implemented, I'm willing to post a script invoking WMI which has already been done on my side. And, I saw here a script controlling IExplore using external library, then, there would be no need to rely on an external library any more, although I'm not sure how complicated it would be to achieve as I haven't done it myself because I seldom use IExplore.

Sean

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I don't see how function pointers in DllCall can help us with COM. Example using mentioned WebBrowser control with imaginary DllCall would help.
Posted Image

Sean
  • Guests
  • Last active:
  • Joined: --

I don't see how function pointers in DllCall can help us with COM. Example using mentioned WebBrowser control with imaginary DllCall would help.


My first example isn't enough?
As I said in the previous message I haven't tried IWebBrowser2 so I can't show the usage about it right now. Instead, I'll post about WMI which has been done already.

Actually there exist two ways to do it. Since MS thinks WMI is so important, MS provides both Interfaces to be used in C/C++ and in scripts. Although the interface for C/C++ is more natural in this approach, I'll use the one for scripts as it'd be the easier one to be adapted to the objects scripters are generally interested in.

It'll enumerate all the network adapters in the system.
(Sorry, I haven't commented it appropriately. Just take it as a showcase.)

sNamespace := "winmgmts:{impersonationLevel=impersonate}!\\.\" . "root\cimv2"
sClass := "SELECT * FROM " . "Win32_NetworkAdapter"
sQLang := "WQL"

VarSetCapacity(wNamespace, StrLen(sNamespace) * 2 + 2)
VarSetCapacity(wClass, StrLen(sClass) * 2 + 2)
VarSetCapacity(wQLang, 8)

Unicode(sNameSpace, wNameSpace, StrLen(sNamespace) + 1)
Unicode(sClass, wClass, StrLen(sClass) + 1)
Unicode(sQLang, wQLang, 4)

EncodeInteger(&IID_IDispatch    , 0x00020400)
EncodeInteger(&IID_IDispatch + 4, 0)
EncodeInteger(&IID_IDispatch + 8, 0xC0)
EncodeInteger(&IID_IDispatch +12, 0x46 << 24)

hModule := DllCall("LoadLibrary", "str", "msjava.dll")

DllCall("ole32\CoInitialize", "Uint", 0)

DllCall("ole32\CoGetObject"
	, "Uint", &wNamespace
	, "Uint", 0
	, "Uint", &IID_IDispatch
	, "UintP", psvc)

DllCall("msjava\call"
	, "Uint", DecodeInteger(DecodeInteger(psvc) + 4*15)
	, "Uint", psvc
	, "Uint", &wClass
	, "Uint", &wQLang
	, "Uint", 48
	, "Uint", 0
	, "UintP", pset)

DllCall("msjava\call"
	, "Uint", DecodeInteger(DecodeInteger(pset) + 4*7)
	, "Uint", pset
	, "UintP", penm)

VarSetCapacity(sText, 10240, 1)
VarSetCapacity(vt, 4 * 4)

Loop
{
    hResult := DllCall("msjava\call"
	, "Uint", DecodeInteger(DecodeInteger(penm) + 4*3)
	, "Uint", penm
	, "Uint", 1
	, "Uint", &vt
	, "Uint", 0)

    If hResult
	break

    pobj := DecodeInteger(&vt + 4*2)

    DllCall("msjava\call"
	, "Uint", DecodeInteger(DecodeInteger(pobj) + 4*22)
	, "Uint", pobj
	, "Uint", 0
	, "UintP", ptr)

    DllCall("WideCharToMultiByte"
	, "Uint", 0
	, "Uint", 0
	, "Uint", ptr
	, "int", -1
	, "Uint", &sText
	, "int", 10240
	, "Uint", 0
	, "Uint", 0)

    DllCall("msjava\call"
	, "Uint", DecodeInteger(DecodeInteger(pobj) + 4*2)
	, "Unit", pobj)

    MsgBox % sText
}


DllCall("msjava\call"
	, "Uint", DecodeInteger(DecodeInteger(pset) + 4*2)
	, "Unit", penm)
DllCall("msjava\call"
	, "Uint", DecodeInteger(DecodeInteger(pset) + 4*2)
	, "Unit", pset)
DllCall("msjava\call"
	, "Uint", DecodeInteger(DecodeInteger(pset) + 4*2)
	, "Unit", psvc)

DllCall("ole32\CoUninitialize")

DllCall("FreeLibrary", "Uint", hModule)


Unicode(ByRef sString, ByRef wString, nLength)
{
  DllCall("MultiByteToWideChar"
	, "Uint", 0
	, "Uint", 0
	, "Uint", &sString
	, "int", -1
	, "Uint", &wString
	, "int", nLength)
}

DecodeInteger(ptr)
{
  DllCall("RtlMoveMemory", "UintP", deref, "Uint", ptr, "Uint", 4)
  Return deref
}

EncodeInteger(ref, val)
{
  DllCall("ntdll\RtlFillMemoryUlong", "Uint", ref, "Uint", 4, "Uint", val)
}


BTW, is this a bug? I have to use VarSetCapacity(sText, 10240, 1) or non-zero byte for the last parameter.
If use VarSetCapacity(sText, 10240) or VarSetCapacity(sText, 10240, 0), then empty sText was returned.

Sean
  • Guests
  • Last active:
  • Joined: --
Oops, my mistake. The last three ones should have been:

DllCall("msjava\call"
   , "Uint", DecodeInteger(DecodeInteger(penm) + 4*2)
   , "Unit", penm)
DllCall("msjava\call"
   , "Uint", DecodeInteger(DecodeInteger(pset) + 4*2)
   , "Unit", pset)
DllCall("msjava\call"
   , "Uint", DecodeInteger(DecodeInteger(psvc) + 4*2)
   , "Unit", psvc) 



majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006

Sorry, I haven't commented it appropriately

Strange way to say that you don't have comments at all... you can safely delete "appropriately".


BTW, is this a bug?

Yes.


Just take it as a showcase.

Hm.... I see that you use dynamic execution using call(). So, U acctually use metaprogramming. C# may be better candidate (Invoke) as msjava.dll is missing from Windows XP due to the Microsoft-Sun agreement on Java technology.

I will check this topic more carefully and let you know what I think.

Thx for nice examples and some new insights.


BTW, as you are not AHK user, why are you posting this ?
Posted Image

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005

BTW, is this a bug? I have to use VarSetCapacity(sText, 10240, 1) or non-zero byte for the last parameter.
If use VarSetCapacity(sText, 10240) or VarSetCapacity(sText, 10240, 0), then empty sText was returned.

It is a known problem, still mysterious for me, but the problem might be in Windows rather than in AHK (just an hypothesis).

As a "non AutoHotkey user", you have quite some knowledge of the language (or at least of the proper use of DllCall and related).

msjava.dll is missing from Windows XP

I checked on a couple of WinXP Pro SP2 computers at work and both have it in System32.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

Sean
  • Guests
  • Last active:
  • Joined: --

C# may be better candidate (Invoke) as msjava.dll is missing from Windows XP due to the Microsoft-Sun agreement on Java technology.


That's (minor) one of the two reasons why I requested the feature.

BTW, as you are not AHK user, why are you posting this ?


'Cause I think I've benefited from AHK, although indirectly.
And I'm thinking about using a second scripting language, mainly for fun. At first, I leaned toward AutoIt, but now I'm definitely attracted toward AHK. I like its C like style.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006

I checked on a couple of WinXP Pro SP2 computers at work and both have it in System32.

I know, I have it too.... but... that is official note. Some service pack or hot fix or anything can remove this dll... Also this dll is not maintaned anymore by MS, and it might have buffer overflows etc...

At first, I leaned toward AutoIt, but now I'm definitely attracted toward AHK. I like its C like style.

C like style ?
Funny ....
AutoIt's syntax capabilities are much better then in AHK, but again, that thing is slow as hell for me, while AHK shines...
Posted Image