Help with COM and AutoCAD Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
phyrburn
Posts: 13
Joined: 24 Jul 2019, 05:55

Help with COM and AutoCAD

24 Jul 2019, 07:11

Hi all,

I'm having an issue with a COM object that outputs data into 2 variables. No matter what I try, the variables are created empty. Not sure if I am missing something syntax wise, or if this is something unsupported by AHK.

AutoCAD drawings support standard file properties such as "Title", "Author", "Revision" and so forth. They also support custom file properties, each being a "key" with a "value". These properties are all accessible via COM through the "SummaryInfo" object. Standard properties are retrievable, and editable. Custom properties are retrievable, editable and can be removed all together.

I can read and change all the standard properties just fine. Custom properties I can add, change and remove, but I cannot seem to read them.

There are two methods to do this.
By index

Code: Select all

aCAD := ComObjActive("AutoCAD.Application")
aCAD.ActiveDocument.SummaryInfo.GetCustomByIndex(0, key, value)
My understanding is that this code should result in a variable name "key" containing the key, and a variable named "value" with the value stored, from the first custom property. Listvars confirms the two variables are created. But they are blank.
By key

Code: Select all

aCAD := ComObjActive("AutoCAD.Application")
aCAD.ActiveDocument.SummaryInfo.GetCustomByKey("key", value)
Likewise, I believe this should give me a variable named "value" containing the value from the key named "key". Again, Listvars shows the variable created, but is blank.

I feel like I am missing something simple here. I haven't had any issue utilising COM in AutoCAD until now.

I have also posted the question in the AutoCAD subreddit.

Thanks in advance.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Help with COM and AutoCAD

24 Jul 2019, 08:41

Try ComVar() function from https://www.autohotkey.com/docs/commands/ComObjActive.htm#Examples

Code: Select all

key := ComVar()
val := ComVar()

aCAD := ComObjActive("AutoCAD.Application")
aCAD.ActiveDocument.SummaryInfo.GetCustomByIndex(0, key.ref, val.ref)
MsgBox % key[] "," val[]

; ComVar: Creates an object which can be used to pass a value ByRef.
;   ComVar[] retrieves the value.
;   ComVar[] := Val sets the value.
;   ComVar.ref retrieves a ByRef object for passing to a COM function.
ComVar(Type=0xC)
{
    static base := { __Get: "ComVarGet", __Set: "ComVarSet", __Delete: "ComVarDel" } ; For base, see Custom Objects.
    ; Create an array of 1 VARIANT.  This method allows built-in code to take
    ; care of all conversions between VARIANT and AutoHotkey internal types.
    arr := ComObjArray(Type, 1)
    ; Lock the array and retrieve a pointer to the VARIANT.
    DllCall("oleaut32\SafeArrayAccessData", "ptr", ComObjValue(arr), "ptr*", arr_data)
    ; Store the array and an object which can be used to pass the VARIANT ByRef.
    return { ref: ComObject(0x4000|Type, arr_data), _: arr, base: base }
}

ComVarGet(cv, p*) { ; Called when script accesses an unknown field.
    if p.MaxIndex() = "" ; No name/parameters, i.e. cv[]
        return cv._[0]
}

ComVarSet(cv, v, p*) { ; Called when script sets an unknown field.
    if p.MaxIndex() = "" ; No name/parameters, i.e. cv[]:=v
        return cv._[0] := v
}

ComVarDel(cv) { ; Called when the object is being freed.
    ; This must be done to allow the internal array to be freed.
    DllCall("oleaut32\SafeArrayUnaccessData", "ptr", ComObjValue(cv._))
}
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Help with COM and AutoCAD

24 Jul 2019, 09:30

@tmplinshi , assuming this works, why is it needed that u do it that way?
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Help with COM and AutoCAD

24 Jul 2019, 09:46

@swagfag I don't have other ways in mind..
phyrburn
Posts: 13
Joined: 24 Jul 2019, 05:55

Re: Help with COM and AutoCAD

24 Jul 2019, 16:40

tmplinshi wrote: Try ComVar() function from https://www.autohotkey.com/docs/commands/ComObjActive.htm#Examples
Thanks for that. I kind of understand the approach here and I hadn't thought of that, but it unfortunately errors out with a "Type Mismatch". It seems the GetCustomByIndex method doesn't accept the ".ref" extension to the variable names.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Help with COM and AutoCAD  Topic is solved

26 Jul 2019, 17:30

Tested and worked. ComVar() creates a VT_VARIANT object by default, we need to create a VT_BSTR to work with GetCustomByIndex.

Code: Select all

aCAD := ComObjActive("AutoCAD.Application")

aCAD.ActiveDocument.SummaryInfo.AddCustomInfo("TestKey", "TestValue")

; https://www.autohotkey.com/docs/commands/ComObjType.htm#vt
; VT_BSTR = 8
key := ComVar(8)
val := ComVar(8)
aCAD.ActiveDocument.SummaryInfo.GetCustomByIndex(0, key.ref, val.ref)
MsgBox % key[] " = " val[]

val := ComVar(8)
aCAD.ActiveDocument.SummaryInfo.GetCustomByKey("TestKey", val.ref)
MsgBox % val[]


; ComVar: Creates an object which can be used to pass a value ByRef.
;   ComVar[] retrieves the value.
;   ComVar[] := Val sets the value.
;   ComVar.ref retrieves a ByRef object for passing to a COM function.
ComVar(Type=0xC)
{
    static base := { __Get: "ComVarGet", __Set: "ComVarSet", __Delete: "ComVarDel" } ; For base, see Custom Objects.
    ; Create an array of 1 VARIANT.  This method allows built-in code to take
    ; care of all conversions between VARIANT and AutoHotkey internal types.
    arr := ComObjArray(Type, 1)
    ; Lock the array and retrieve a pointer to the VARIANT.
    DllCall("oleaut32\SafeArrayAccessData", "ptr", ComObjValue(arr), "ptr*", arr_data)
    ; Store the array and an object which can be used to pass the VARIANT ByRef.
    return { ref: ComObject(0x4000|Type, arr_data), _: arr, base: base }
}

ComVarGet(cv, p*) { ; Called when script accesses an unknown field.
    if p.MaxIndex() = "" ; No name/parameters, i.e. cv[]
        return cv._[0]
}

ComVarSet(cv, v, p*) { ; Called when script sets an unknown field.
    if p.MaxIndex() = "" ; No name/parameters, i.e. cv[]:=v
        return cv._[0] := v
}

ComVarDel(cv) { ; Called when the object is being freed.
    ; This must be done to allow the internal array to be freed.
    DllCall("oleaut32\SafeArrayUnaccessData", "ptr", ComObjValue(cv._))
}
You may encounter similar problems like this, with different data types.
To know what data type to use, firstly you look up the AutoCAD documentation, for example GetCustomByIndex Method (ActiveX)
RetVal = object.GetCustomByIndex(Index, pKey, pValue)

pKey
Access: Output-only

Type: String

The custom property name that corresponds to the index value.
So the type is string, then you find a corresponding type from https://www.autohotkey.com/docs/commands/ComObjType.htm#vt.

Another example of using AutoCAD: https://www.autohotkey.com/boards/viewtopic.php?t=37462#p174336
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Help with COM and AutoCAD

28 Jul 2019, 07:26

so do all BSTR variant outparams have to be retrieved this way?
in the docs i found https://www.autohotkey.com/docs/commands/ComObjActive.htm#ByRef
would this work too?

Code: Select all

VT_BSTR := 0x8
VT_BYREF := 0x4000

VarSetCapacity(var, ????, 0)
vref := ComObject(VT_BYREF | VT_BSTR, &var)

aCAD.ActiveDocument.SummaryInfo.GetCustomByKey("TestKey", vref)
MsgBox % vref[]
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Help with COM and AutoCAD

28 Jul 2019, 08:26

No idea, I have uninstalled AutoCAD.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Help with COM and AutoCAD

28 Jul 2019, 08:28

do u know of another COM api function that has byref outparams? word, excel?
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Help with COM and AutoCAD

28 Jul 2019, 08:43

Ok, I remembered one of my replies:
https://www.autohotkey.com/boards/viewtopic.php?p=98300#p98300

Code: Select all

FileName := A_ScriptDir "\test.mdb"

conn := ComObjCreate("ADODB.Connection")
conn.Open("Driver={Microsoft Access Driver (*.mdb)}; DBQ=" FileName)
sql := "UPDATE mytable SET MyField = 'MyValue' WHERE MyKey = '1'"

RecordsAffected := ComVar_Long()
conn.Execute(Sql, RecordsAffected)
conn.Close()
MsgBox, % RecordsAffected[]
Return

ComVar_Long() {
	VarSetCapacity(var, 4, 0)
	return ComObject(0x4003, &var) ; 0x4003 = VT_BYREF|VT_I4
}
phyrburn
Posts: 13
Joined: 24 Jul 2019, 05:55

Re: Help with COM and AutoCAD

29 Jul 2019, 19:00

tmplinshi wrote: Tested and worked. ComVar() creates a VT_VARIANT object by default, we need to create a VT_BSTR to work with GetCustomByIndex.
Wow. Thank you so much @tmplinshi. That is perfect. I've had a good read of everything you've linked and I will keep going through it, but I understand your explanation pretty well, and there are even a couple of other AutoCAD methods that I haven't been able to get to work in the past that I think I'll be able to get sorted now.

I still have a lot of learning to do, but people like you make this so much easier with explanations like this.
:bravo:

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 188 guests