 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
tfcahm
Joined: 20 May 2007 Posts: 48
|
Posted: Wed Jul 04, 2007 2:55 am Post subject: |
|
|
| Quote: | | OK, I'd like to leave it to you. | Alright. May be a few days before I get to it. Obviously it will be more complicated than the current function.
| Quote: | | first byte of the allocated varg will be erased | Got it. Thanks!
| Quote: | I'm not sure if it's AHK's problem.
I'm suspecting that BookCat may have a bug to manage a buffer, as I think that the original script using the VTable interface would have worked already otherwise. | Could be. BookCAT's author seems very responsive, so with a good definition of the problem I expect it will get fixed. |
|
| Back to top |
|
 |
tfcahm
Joined: 20 May 2007 Posts: 48
|
Posted: Sat Jul 07, 2007 3:12 pm Post subject: |
|
|
Sean,
The problems with memory errors, and other strange goings-on in my script are resolved. The guy who provided the original Perl code came up with the answer. The ByRef strings need to be cleared with a VariantClear dll call. Seems logical there should be a VariantInit to go with it, but this works flawlessly as is. The code below is an updated version of the code you posted above. It is also has the offsets modified to work with the July 5 version of Invoke(). Thanks again for originally posting this code as it was the key to me being able to move forward with my own.
| Code: | #Include CoHelper.ahk
CoInitialize()
pds := ActiveXObject("BookCAT.DataServer")
sXSLTemplate := "BookList.xsl"
sFilter := "Author=John Grisham"
sFilename := ""
sRecordset := ""
bStripLinks := False
pXSLTemplate := SysAllocString(sXSLTemplate)
pFilter := SysAllocString(sFilter)
pFilename := SysAllocString(sFilename)
pRecordset := SysAllocString(sRecordset)
VarSetCapacity(var, 88, 0)
var := Chr(5)
NumPut(8|0x4000, var, 1), NumPut(&var+81, var, 9)
NumPut(8|0x4000, var,17), NumPut(&var+84 ,var,25)
NumPut(11,var, 33), NumPut(-bStripLinks, var, 41, "short")
NumPut(8, var, 49), NumPut(pFilter , var, 57)
NumPut(8, var, 65), NumPut(pXSLTemplate, var, 73)
NumPut(pRecordset, var, 81), NumPut(pFilename, var, 85)
nResult := Invoke(pds, "GenerateHTML", &var)
Unicode2Ansi(pstr1 := NumGet(var, 81), sRecordset)
Unicode2Ansi(pstr2 := NumGet(var, 85), sFilename)
SysFreeString(pXSLTemplate)
SysFreeString(pFilter)
DllCall("oleaut32.dll\VariantClear","UInt",pFilename)
DllCall("oleaut32.dll\VariantClear","UInt",pRecordset)
; do other stuff...
Release(pds)
CoUninitialize()
MsgBox, % "GenerateHtml`n Filename: " . sFilename . "`n Recordset: " . sRecordset |
I would be interested in using COM event if added to CoHelper. CoHelper and the example scripts you've shared are a great asset. Don't be detered by those who don't want to take the time to learn it. Every one of the example codes teaches something new. It took me a while to see how it all goes together, but that effort is paying off now. Thanks again for CoHelper, and for your example scripts. |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Sat Jul 07, 2007 5:26 pm Post subject: |
|
|
| tfcahm wrote: | | The problems with memory errors, and other strange goings-on in my script are resolved. |
Nice!
| Quote: | | The guy who provided the original Perl code came up with the answer. The ByRef strings need to be cleared with a VariantClear dll call. |
That's a bit strange. pFilename and pRecordset are not variant themselves...
Anyway, what VariantClear does in this case is to SysFreeString on pFilename and pRecordset, I beleive. Looks like I forgot to do that ...
| Code: | #Include CoHelper.ahk
CoInitialize()
pds := ActiveXObject("BookCAT.DataServer")
sXSLTemplate := "BookList.xsl"
sFilter := "Author=John Grisham"
sFilename := ""
sRecordset := ""
bStripLinks := False
pXSLTemplate := SysAllocString(sXSLTemplate)
pFilter := SysAllocString(sFilter)
pFilename := SysAllocString(sFilename)
pRecordset := SysAllocString(sRecordset)
VarSetCapacity(var, 88, 0)
var := Chr(5)
NumPut(8|0x4000, var, 1), NumPut(&var+81, var, 9)
NumPut(8|0x4000, var,17), NumPut(&var+84 ,var,25)
NumPut(11,var, 33), NumPut(-bStripLinks, var, 41, "short")
NumPut(8, var, 49), NumPut(pFilter , var, 57)
NumPut(8, var, 65), NumPut(pXSLTemplate, var, 73)
NumPut(pRecordset, var, 81), NumPut(pFilename, var, 85)
nResult := Invoke(pds, "GenerateHTML", &var)
Unicode2Ansi(pstr1 := NumGet(var, 81), sRecordset)
Unicode2Ansi(pstr2 := NumGet(var, 85), sFilename)
SysFreeString(pXSLTemplate)
SysFreeString(pFilter)
DllCall("oleaut32.dll\VariantClear","UInt",pFilename)
DllCall("oleaut32.dll\VariantClear","UInt",pRecordset)
; do other stuff...
Release(pds)
CoUninitialize()
MsgBox, % "GenerateHtml`n Filename: " . sFilename . "`n Recordset: " . sRecordset |
| Quote: | | It is also has the offsets modified to work with the July 5 version of Invoke(). |
You really managed well with the unnatural 1byte offset shift. This is the best I can do atm without taking the full route of the dispatch interface.
But, I think it's better than the previous one like varg:=DispParams(num, varg, ...), as it would be hidden from the scene mostly, like:
| Code: | VarSetCapacity(ref, 8), NumPut(pFilename, ref, 0), NumPut(pRecordset, ref, 4)
nResult := Invoke(pds, "GenerateHTML", DispParams(varg, 8, pXSLTemplate, 8, pFilter, 11, -bStripLinks, 8|0x4000, &ref, 8|0x4000, &ref+4))
Unicode2Ansi(pstr1 := NumGet(ref, 0), sFilename)
Unicode2Ansi(pstr2 := NumGet(ref, 4), sRecordset)
|
| Quote: | | I would be interested in using COM event if added to CoHelper. CoHelper and the example scripts you've shared are a great asset. |
Maybe I can PM you the code later. Actually, it can be achieved without the long detour, for many cases. However, it's not 100% guaranteed. To make it work in any cases forced to take very tedious steps. I'm thinking about currently if there is any way to make it simpler.
And, thank you for the warm words! |
|
| Back to top |
|
 |
tfcahm
Joined: 20 May 2007 Posts: 48
|
Posted: Sat Jul 07, 2007 6:39 pm Post subject: |
|
|
| Sean wrote: | That's a bit strange. pFilename and pRecordset are not variant themselves...
Anyway, what VariantClear does in this case is to SysFreeString on pFilename and pRecordset, I beleive. Looks like I forgot to do that ... | Actually, you did have SysFreeString on pFilename and pRecordset. In this case that apparently did not free them.
| Quote: | You really managed well with the unnatural 1byte offset shift. This is the best I can do atm without taking the full route of the dispatch interface.
But, I think it's better than the previous one like varg:=DispParams(num, varg, ...), as it would be hidden from the scene mostly, like:
| Code: | VarSetCapacity(ref, 8), NumPut(pFilename, ref, 0), NumPut(pRecordset, ref, 4)
nResult := Invoke(pds, "GenerateHTML", DispParams(varg, 8, pXSLTemplate, 8, pFilter, 11, -bStripLinks, 8|0x4000, &ref, 8|0x4000, &ref+4))
Unicode2Ansi(pstr1 := NumGet(ref, 0), sFilename)
Unicode2Ansi(pstr2 := NumGet(ref, 4), sRecordset)
|
| Nice! I hadn't gone back to figure out how to do that using DispParams() yet. Thanks for the example.
| Quote: | | Maybe I can PM you the code later. | Much appreciated. No rush, I'm not quite ready for it anyway. |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Sun Jul 08, 2007 4:02 am Post subject: |
|
|
| tfcahm wrote: | | Actually, you did have SysFreeString on pFilename and pRecordset. In this case that apparently did not free them. |
Then, I got the feeling that SysFreeString on ByRef parameters in this case should not be applied, may be handled by BookCat itself.
So, simply removing those lines might cure the symptom.
| Quote: | | Nice! I hadn't gone back to figure out how to do that using DispParams() yet. Thanks for the example. |
I think it can be simplified a bit further.
| Code: | VarSetCapacity(ref, 8)
nResult := Invoke(pds, "GenerateHTML", DispParams(varg, 8, pXSLTemplate, 8, pFilter, 11, -bStripLinks, 8|0x4000, NumPut(pFilename, ref, 0)-4, 8|0x4000, NumPut(pRecordset, ref, 4)-4))
Unicode2Ansi(pstr1 := NumGet(ref, 0), sFilename)
Unicode2Ansi(pstr2 := NumGet(ref, 4), sRecordset)
|
|
|
| Back to top |
|
 |
tfcahm
Joined: 20 May 2007 Posts: 48
|
Posted: Sun Jul 08, 2007 5:28 am Post subject: |
|
|
| Quote: | Then, I got the feeling that SysFreeString on ByRef parameters in this case should not be applied, may be handled by BookCat itself.
So, simply removing those lines might cure the symptom. |
Brilliant! That works. Mystery solved. Guess the VariantClear was acting as a no-op in this case. |
|
| Back to top |
|
 |
erictheturtle
Joined: 27 Jun 2007 Posts: 101 Location: California
|
Posted: Sat Jul 14, 2007 4:00 pm Post subject: |
|
|
Hi Sean,
I wanted to ask you what the purpose of the GetIDispatch() function is in COMHelper.ahk.
Sudo code | Code: | GetIDispatch(ppv)
{
ppv->GetTypeInfoCount(&cti)
if (!cti)
return
ppv->GetTypeInfo(0, LCID, &pti)
pti->GetTypeAttr(&pattr)
ppv->QueryInterface(pattr->guid, &pdisp)
pti->ReleaseTypeAttr(pattr)
pti->Release()
if (pdisp)
ppv->Release()
return pdisp
} |
I found similar code here with the explaination of "Try to QueryInterface a COM pointer to the 'most useful' interface" and "find the interface marked as default". What advantages do you get from performing this step over just using the original IDispatch ppv? _________________ -m35 |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Sat Jul 14, 2007 10:13 pm Post subject: |
|
|
| erictheturtle wrote: | | What advantages do you get from performing this step over just using the original IDispatch ppv? |
It's redundant mostly. So, I didn't add it to ActiveXObject etc at first, but decided to add it later to not cause a confusion as it would do no harm anyway, just superfluous.
If a COM server resides in another process and you're going to use VTBL interface of it, then this step is necessary. |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Thu Jul 26, 2007 5:00 am Post subject: |
|
|
| Sean wrote: | | tfcahm wrote: | | I really like this. If you don't do it first, I'd like to extend it to handle BYREFs. | OK, I'd like to leave it to you. |
OK, I implemented VT_BYREF too in Invoke_(). So, please test it:
| Code: | #Include CoHelper.ahk
sXSLTemplate := "BookList.xsl"
sFilter := "Author=John Grisham"
bStripLinks := False
CoInitialize()
pds := ActiveXObject("BookCAT.DataServer")
nResult := Invoke_(pds, "GenerateHTML", 8, sXSLTemplate, 8, sFilter, 11, bStripLinks, 8|0x4000, "", 8|0x4000, "")
sFilename := _TEMP_VT_BYREF_4
sRecordset := _TEMP_VT_BYREF_5
Release(pds)
CoUninitialize()
MsgBox, % "GenerateHtml`n Filename: " . sFilename . "`n Recordset: " . sRecordset
|
The returned result will be saved in the global variables _TEMP_VT_BYREF_%A_Index%, where the index is the argument's position in the function. |
|
| Back to top |
|
 |
tfcahm
Joined: 20 May 2007 Posts: 48
|
Posted: Thu Jul 26, 2007 6:37 am Post subject: |
|
|
| Sean wrote: | | OK, I implemented VT_BYREF too in Invoke_(). | Wow...unexpected. Thanks!
It runs perfectly as you wrote it above, but strangely it does not work properly as a function. The values for _TEMP_VT_BYREF_n are blank. The GenerateHTML method in BookCAT runs properly and returns the correct nResult, so the only issue is the blank _TEMP_VT_BYREF_ values. I used edit 37 of CoHelper for this test. | Code: | #Include CoHelper.ahk
nResult := GenHTML()
ExitApp
GenHTML() {
sXSLTemplate := "BookList.xsl"
sFilter := "Author=John Grisham"
bStripLinks := False
CoInitialize()
pds := ActiveXObject("BookCAT.DataServer")
nResult := Invoke_(pds, "GenerateHTML", 8, sXSLTemplate, 8, sFilter, 11, bStripLinks, 8|0x4000, "", 8|0x4000, "")
sFilename := _TEMP_VT_BYREF_4
sRecordset := _TEMP_VT_BYREF_5
Release(pds)
CoUninitialize()
MsgBox, % "GenerateHtml`n Filename: " . sFilename . "`n Recordset: " . sRecordset
Return nResult
} |
|
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Thu Jul 26, 2007 8:49 am Post subject: |
|
|
| tfcahm wrote: | | It runs perfectly as you wrote it above, but strangely it does not work properly as a function. The values for _TEMP_VT_BYREF_n are blank. |
_TEMP_VT_BYREF_%A_Index% is dynamically generated global variables inside Invoke_(). So, if you want to refer it inside functions, you have to declare them as Global. In this case, add the following at the start of the function:
| Code: | | Global _TEMP_VT_BYREF_4, _TEMP_VT_BYREF_5 |
PS. To me, there is an unclear point with VT_BYREF parameters.
Namely, still can expect type-coercions with VT_BYREF parameters?
Do you know of an app which uses other than bstr as ByRef?
I mean, it expects VT_R8|VT_BYREF, but we can specify it with VT_BSTR|VT_BYREF.
Then, OLE manger correctly type-coerced it and give to the function.
If so, how about the returned values? Will it be VT_R8 or VT_BSTR? |
|
| Back to top |
|
 |
erictheturtle
Joined: 27 Jun 2007 Posts: 101 Location: California
|
Posted: Thu Jul 26, 2007 12:57 pm Post subject: |
|
|
In my tests with the home-made COM object, I had a method like this
| Code: | Public Sub RefArgs(ByRef str As String, ByRef i As Integer)
str = "return a string"
i = 4444
End Sub |
When I Invoked this method with VT_BYREF|VT_BSTR and VT_BYREF|VT_I4, it failed saying the integer argument could not be coerced. When I changed the parameter to be "ByRef i as Long", then the Invoke succeeded. This let me to conclude that Invoke does not perform type coercion on ByRef parameters. _________________ -m35 |
|
| Back to top |
|
 |
tfcahm
Joined: 20 May 2007 Posts: 48
|
Posted: Thu Jul 26, 2007 2:05 pm Post subject: |
|
|
| Sean wrote: | | _TEMP_VT_BYREF_%A_Index% is dynamically generated global variables inside Invoke_(). | I completely missed that...working too late. Thanks.
| Sean wrote: | | Do you know of an app which uses other than bstr as ByRef? | Nero has some ByRef as Variants. I haven't tried it. |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Thu Jul 26, 2007 10:51 pm Post subject: |
|
|
| erictheturtle wrote: | | When I Invoked this method with VT_BYREF|VT_BSTR and VT_BYREF|VT_I4, it failed saying the integer argument could not be coerced. When I changed the parameter to be "ByRef i as Long", then the Invoke succeeded. This let me to conclude that Invoke does not perform type coercion on ByRef parameters. |
Thanks for the test. I first added the coercion code into the return value of ByRef code without thinking, but after thinking it started to make little sense to me, so I removed it immediately. |
|
| Back to top |
|
 |
polyethene
Joined: 11 Aug 2004 Posts: 5248 Location: UK
|
Posted: Wed Aug 22, 2007 6:22 pm Post subject: |
|
|
I like the updates, Invoke() and ActiveXObject() will make things a lot easier. Could you also add garbage collection during uninitialization so we don't have to manually release each object. _________________ GitHub • Scripts • IronAHK • Contact by email not private message. |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|