- NSIS Discussion
- Playing with COM
Archive: Playing with COM
Zinthose
19th August 2010 20:12 UTC
Playing with COM
I'm attempting to recreate the example posted at: http://en.wikipedia.org/wiki/OLE_Automation#Examples
My code is choking at GetIDsOfNames... Can anyone add some insight?
/*
!define IID_StdOle '{00020430-0000-0000-C000-000000000046}'
!define IID_IDispatch '{00020400-0000-0000-C000-000000000046}'
!define IID_IUnknown '{00000000-0000-0000-C000-000000000046}'
!define IID_NULL '{00000000-0000-0000-0000-000000000000}'
!define CLSCTX_SERVER 0x015
!define LOCALE_SYSTEM_DEFAULT 0x800
*/
DetailPrint CLSIDFromProgID
System
::Call `Ole32::CLSIDFromProgID(w,&g16)i ("Excel.Application",.r0).r2`
DetailPrint "ERR=$2"
DetailPrint "CLSID=$0"
DetailPrint CoCreateInstance
System::Call `Ole32::CoCreateInstance(g r0,i 0,i ${CLSCTX_SERVER},g '${IID_IDispatch}',*i .r1) i .r2`
DetailPrint "ERR=$2"
DetailPrint GetIDsOfNames
System::Call `$1->GetIDsOfNames(g ${IID_NULL},w "Visible",i 1,i ${LOCALE_SYSTEM_DEFAULT},*i .r3)i .r2` ;<-- Errors here... :'(
DetailPrint "ERR=$2" ; <-- I'm getting error 0x80004002 (AKA E_NOINTERFACE)
DetailPrint $$3=$3
>
Animaether
19th August 2010 20:24 UTC
Originally posted by Zinthose
My code is choking at GetIDsOfNames... Can anyone add some insight?
System::Call `$1->***91;B***93;GetIDsOfNames***91;/B***93;(g ${IID_NULL},w "Visible",i 1,i ${LOCALE_SYSTEM_DEFAULT},*i .r3)i .r2` ;<-- Errors here... :'(
DetailPrint "ERR=$2" ; <-- I'
m getting error 0x80004002 (AKA E_NOINTERFACE)
GetIDsOfNames should be replaced by the numerical entry of that bit in the interface. I don't recall where you can find that, though..
Afrow UK
19th August 2010 21:24 UTC
It's the zero-based index of the method as it is listed physically in the interface. This includes methods from interfaces that the interface you are using implements. As IUnknown has 3 methods, your first interface method will typically be #3.
Stu
Animaether
19th August 2010 21:32 UTC
Originally posted by Afrow UK
It's the zero-based index of the method as it is listed physically in the interface. This includes methods from interfaces that the interface you are using implements. As IUnknown has 3 methods, your first interface method will typically be #3.
Right - as per the System plugin docs;
To find out the index of a member in a COM interface, you need to search for the definition of this COM interface in the header files that come with Visual C/C++ or the Platform SDK. Remember the index is zero based.
What I meant was.. I don't recall where the header files for this interface can be found online (many of us don't actually touch the SDK bits and pieces) - but then I remembered; WINE usually has 'm :)
http://source.winehq.org/source/include/oleauto.h
Zinthose
19th August 2010 21:40 UTC
Aight... Using the VTable index to lookup the interfaces methods I have now updated with the following..
DetailPrint"== CLSIDFromProgID =="
System::Call `Ole32::CLSIDFromProgID(w,&g16)i ("Excel.Application",.r0).r2`
DetailPrint " ERR=$2"
DetailPrint " CLSID=$0"
DetailPrint "== CoCreateInstance =="
System::Call `Ole32::CoCreateInstance(g r0,i 0,i ${CLSCTX_SERVER},g '${IID_IDispatch}',*i .r1) i .r2`
DetailPrint " ERR=$2"
DetailPrint "== IUnknown::GetTypeInfoCount =="
System::Call `$1->3(*i .r3)i .r2`
DetailPrint " ERR=$2"
DetailPrint " $$3=$3"
DetailPrint "== IDispatch::GetTypeInfo =="
System::Call `$1->4(i 0,i ${LOCALE_SYSTEM_DEFAULT},*i .r3)i .r2`
DetailPrint " ERR=$2"
DetailPrint " $$3=$3"
DetailPrint "== IDispatch::GetIDsOfNames =="
;System::Call `*(i 7,w "Visible")i .s`
;System::Call `$1->5(g ${IID_NULL},i s,i 1,i ${LOCALE_SYSTEM_DEFAULT},*i .r3)i .r2` ;<-- Errors here... :'(
System::Call `$1->5(g ${IID_NULL},w "Visible",i 1,i ${LOCALE_SYSTEM_DEFAULT},*i .r3)i .r2` ;<-- Errors here... :'(
DetailPrint " ERR=$2"
DetailPrint " $$3=$3"
I think the issue may be with the BSTR. I tried creating it manually but I think I'm doint it wrong too.. :/
UPDATE: I'm convinced it is the BSTR.. Reading up on how to implement them now...
http://msdn.microsoft.com/en-us/library/ms221069.aspx
gringoloco023
19th August 2010 21:48 UTC
Is it index 6 ? See, http://www.clarionopensource.com/Cla...hInterface.htm
I was recently fighting with something similar, ITypeLib :)
Zinthose
19th August 2010 23:12 UTC
Woot! It was the BSTR!
DetailPrint "== CLSIDFromProgID =="
System::Call `Ole32::CLSIDFromProgID(w,&g16)i ("Excel.Application",.r0).r2`
DetailPrint " ERR=$2"
DetailPrint " CLSID=$0"
DetailPrint "== CoCreateInstance =="
System::Call `Ole32::CoCreateInstance(g r0,i 0,i ${CLSCTX_SERVER},g '${IID_IDispatch}',*i .r1) i .r2`
DetailPrint " ERR=$2"
DetailPrint "== IUnknown::GetTypeInfoCount =="
System::Call `$1->3(*i .r3)i .r2`
DetailPrint " ERR=$2"
DetailPrint " $$3=$3"
DetailPrint "== IDispatch::GetTypeInfo =="
System::Call `$1->4(i 0,i ${LOCALE_SYSTEM_DEFAULT},*g .r3)i .r2`
DetailPrint " ERR=$2"
DetailPrint " $$3=$3"
DetailPrint "== BSTR =="
System::Call `Oleaut32::SysAllocString(w "Visible")i .s`
DetailPrint "== IDispatch::GetIDsOfNames =="
System::Call `$1->5(g ${IID_NULL},*i s,i 1,i ${LOCALE_SYSTEM_DEFAULT},*i .r3)i .r2` ;<-- Errors here... :(
DetailPrint " ERR=$2"
DetailPrint " $$3=$3"
Now to work out the rest... ;)
Zinthose
19th August 2010 23:23 UTC
Just a warning... if anyone is playing around with this.. check your TaskManager.. I just found 23 instances of Excel running..... :eek:
Here is the updated code with the COM Release at the end.
DetailPrint"== CLSIDFromProgID =="
System::Call `Ole32::CLSIDFromProgID(w,&g16)i ("Excel.Application",.r0).r2`
DetailPrint " ERR=$2"
DetailPrint " CLSID=$0"
DetailPrint "== CoCreateInstance =="
System::Call `Ole32::CoCreateInstance(g r0,i 0,i ${CLSCTX_SERVER},g '${IID_IDispatch}',*i .r1) i .r2`
DetailPrint " ERR=$2"
DetailPrint "== IDispatch::GetTypeInfoCount =="
System::Call `$1->3(*i .r3)i .r2`
DetailPrint " ERR=$2"
DetailPrint " $$3=$3"
DetailPrint "== IDispatch::GetTypeInfo =="
System::Call `$1->4(i 0,i ${LOCALE_SYSTEM_DEFAULT},*g .r3)i .r2`
DetailPrint " ERR=$2"
DetailPrint " $$3=$3"
DetailPrint "== Oleaut32::SysAllocString =="
System::Call `Oleaut32::SysAllocString(w "Visible")i .r4`
DetailPrint " RC=$4"
DetailPrint "== IDispatch::GetIDsOfNames =="
System::Call `$1->5(g ${IID_NULL},*i r4,i 1,i ${LOCALE_SYSTEM_DEFAULT},*i .r3)i .r2` ;<-- Errors here... :(
DetailPrint " ERR=$2"
DetailPrint " $$3=$3"
DetailPrint "== Oleaut32::SysFreeString =="
System::Call `Oleaut32::SysFreeString(*i r4)`
DetailPrint "== IUnknown::Release =="
System::Call `$1->2()i .r2`
DetailPrint " RefCount=$2"
Animaether
19th August 2010 23:58 UTC
heehee
good job :)
one thing you might want to do, just for readability, is defining the interface bits.. e.g.
!define GetIDsOfNames 5
or even
!define IDispatch->GetIDsOfNames 5
Then later on you can just use..
${IDispatch->GetIDsOfNames} (g ${IID_NULL, etc.
..bit cleaner to read :)
Zinthose
20th August 2010 00:56 UTC
Good idea!!
Here is what I thew together.. needs more optimizations but it's a good start..
## Simplyfy the Evil that is COM
## Example:
## ${IDispatch::GetTypeInfo} $1 `(i 0,i ${LOCALE_SYSTEM_DEFAULT},*g .r3)i .r2`
!macro _COM_Function _vTableID _ObjectPointer _Parameters
System::Call `${_ObjectPointer}->${_vTableID}${_Parameters}`
!macroend
!define IUnknown::Release `!insertmacro _COM_Function 2 `
!define IDispatch::GetTypeInfoCount `!insertmacro _COM_Function 3 `
!define IDispatch::GetTypeInfo `!insertmacro _COM_Function 4 `
!define IDispatch::GetIDsOfNames `!insertmacro _COM_Function 5 `
!define IDispatch::Invoke `!insertmacro _COM_Function 6 `
Anders
20th August 2010 18:27 UTC
I have been using some helper macros that are very similar to this (See http://nsis.pastebin.com/BqQFTRv3 ) but I also declare the parameter types in my "_COM_Function" macro so you don't have to specify them when you invoke the method (Can also be used to set default parameter values IIRC) I also use -> and not ::. It might be a good idea to come up with a standard and include it in some header (There is no way we can define all COM interfaces, but some of the shell interfaces would be a good start)