Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

COM Helper


  • This topic is locked This topic is locked
112 replies to this topic
Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007
This is a collection of helper functions to be used for COM. Please save it as CoHelper.ahk.

REDIRECT. CoHelper.ahk is now retired. Use instead COM Standard Library.

Good examples of its usage are:[*:3vhaalq5]Scripting.Dictionary Object as Associative Array
[*:3vhaalq5]Embed an Internet Explorer control in your AHK Gui via COM

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Looks interesting. Could you add some explanations, what the functions do? At least a URL to the relevant MSDN site.

Also, as discussed several times before, the line
Return *ptr | *++ptr << 8 | *++ptr << 16 | *++ptr << 24
relies on undocumented AHK features (the order of evaluation of the terms in expressions). They may change in the future, without appearing in the change log. It looks safer to use
Return *ptr | *(ptr+1) << 8 | *(ptr+2) << 16 | *(ptr+3) << 24


jonny
  • Members
  • 2951 posts
  • Last active: Feb 24 2008 04:22 AM
  • Joined: 13 Nov 2004
Actually, the documentation is pretty clear that it will be evaluated in left-to-right order.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

Actually, the documentation is pretty clear that it will be evaluated in left-to-right order.

All I found in the documentation is:

Operators of equal precedence such as multiply (*) and divide (/) are evaluated in left-to-right order unless otherwise specified

It does not say anything about the order terms are evaluated, only that exp1+exp2+exp3 = (exp1+exp2)+exp3. It is possible that exp3 is evaluated first, pushed on the stack, than exp2 and finally exp1. At this point pop the two topmost stack entries, add them together (exp1+exp2), then pop the third stack entry and add it to the result. It makes a difference if the sub-expressions have side effects, like *++p.

Unless there is an explicit statement in the documentation, that sub-expressions are evaluated from left to right, and none of them is left out, even if they don't affect the result (0*f(x)), it is dangerous to rely on these. Even if it will be documented in the future, using side effects is bad style, and should be avoided when feasible.

Look at the case, which is documented:

When AND, OR, and the ternary operator are used within an expression, they short-circuit to enhance performance (regardless of whether any function calls are present). Short-circuiting operates by refusing to evaluate parts of an expression that cannot possibly affect its final result.

It means, that the following expressions can result in different values of ptr
*ptr  | *++ptr << 8  | *++ptr << 16  | *++ptr << 24
*ptr || *++ptr << 8 || *++ptr << 16 || *++ptr << 24
The second one might not increment ptr at all.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Lazslo, take a look here. Read the article.


2 Sean
I see you have CreateObject function, pandan from VBScript. This fun in VB takes only 1 parameter, progID and somehow determines witch interface to use. Do you maybe understand how it finds the interface ?

BTW, Sean, you should put available functions in the header of the file, this way
Posted Image

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

2 Sean
I see you have CreateObject function, pandan from VBScript. This fun in VB takes only 1 parameter, progID and somehow determines witch interface to use. Do you maybe understand how it finds the interface ?

My IP seems suddenly banned from the forum, the reason is yet to be known. I'm not sure if allowed to post, so, I'll briefly answered.

I think what I'm doing is nearly mimics what VBS engine does: use TypeLib. The only difference may be that I have to do it manually.
For example, with WMI case, retrieve the info about the TypeLib from the registry, which resides in WbemDisp.tlb (:I think vbs actually uses the GUID of the TypeLib to LoadRegTypeLib), then find the default interface is IID_ISWbemLocator of the coclass SWbemLocator.

BTW, Sean, you should put available functions in the header of the file, this way

OK, I'll do that if I'm allowed.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I thought typelibs are connected to interfaces not objects, as one object can have multiple interfaces.
Posted Image

foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006
I like it that you create wrappers around the dll calls but please name the functions the same as the wrapped functions. Having to remember 2 different names for 1 function is a PITA. It would be much better if you could read on msdn and start typing the functions names out as they apear on msdn rather than have to look what the wrapper function is called in your lib.

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

I explaind here how to crate API wrappers.

But foom, i think this is only temporary wrapper. At the end, we will, with little luck, need only 2 or 3 functions: CreateObject, Invoke and SetField
Posted Image

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

Lazslo, take a look here. Read the article.

My point was, that this is a separate thread. Having read the first post I have no idea what is the function library for, let alone the individual functions. It might be enough to say that we should not care, they are used internally by scripts posted elsewhere, but just saying COM is not enough, because it has many meanings. Here it means Component Object Model, but it can mean other things, like Comedy Central (a cable television channel) or Computer output on microfilm.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Sean is the new guy here, not zombie like you :D He needs time.

Anyway thats why I urge him to put things in wiki along with this place.
Posted Image

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

Also, as discussed several times before, the line

Return *ptr | *++ptr << 8 | *++ptr << 16 | *++ptr << 24
relies on undocumented AHK features (the order of evaluation of the terms in expressions). They may change in the future, without appearing in the change log.


I took it from the help file:

Pre- and post-increment/decrement. Adds or subtracts 1 from a variable (but in versions prior to 1.0.46, these can be used only by themselves on a line; no other operators may be present). The operator may appear either before or after the variable's name. If it appears before the name, the operation is performed immediately and its result is used by the next operation. For example, Var := ++X increments X immediately and then assigns its value to Var. Conversely, if the operator appears after the variable's name, the operation is performed after the variable is used by the next operation. For example, Var := X++ increments X only after assigning the current value of X to Var.

IMHO, it explains pretty clearly about the usage. Am I missing something here?

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

Am I missing something here?

Yes. The order in which sub-expressions are evaluated is not specified. There are 4 of them in the top level
*ptr | *++ptr << 8 | *++ptr << 16 | *++ptr << 24
Nothing guaranties that *ptr is first evaluated or *++ptr << 24, in which case you would miss the first address.

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

Am I missing something here?

Yes. The order in which sub-expressions are evaluated is not specified. There are 4 of them in the top level

So, what you're saying is that the operations should apply by their precedence as whole.
For example, consider

SetFormat, Integer, H
var := 1
MsgBox % var | ++var << 8 | ++var << 16 | ++var << 24

According to your rule, the first, second, third ++ apply first, then first, second, third << apply, then finally all |'s apply. Then, the result would become
0x04030204

On the other hand, what I'm thinking is that the operation should apply from left to right according to their precedence. What I mean is that, with the above example, when meet the first operator, the first | in this case, parse the next operator and if it's of higher precedence then, defer the procedure and go on until meeting an operator of lower or equal precedence. Then stop there and apply all the operations accordingly.

So, with the above example, first apply the first ++, then the first <<, then the first |. After that, the second ++, the second <<, the second |. Finally, the third ++, the third <<, the third |. The result would be
0x04030202

What AHK actually produces is 0x04030202.

In conclusion, AHK seems to use the rule of mine, which is more logical IMHO.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
I did not state any rule of expression evaluation, but merely pointed out, that the current AHK behavior is not documented. (Try to read my post more carefully.) In f(x)+f(y) you can evaluate f(x) or f(y) first. Both are conform to the documentation. If your code relies on f(x) being computed the first, it could break at the next AHK release. I don't say it will happen, but could.

If you say that the current evaluation order should be the rule, try to convince Chris to document it and promise that it will not change (very often).

It does not make bad coding style (relying on side effects) good. They make the code hard to understand, debug, modify or optimize. Especially in this case, when it is faster, simpler, safer to use explicit offsets, like *(ptr+1).