Skip to content
⌘ NSIS Forum Archive

Playing with COM

11 posts

Zinthose#

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#
Originally Posted by Zinthose View Post
My code is choking at GetIDsOfNames... Can anyone add some insight?

    System::Call `$1->[B]GetIDsOfNames[/B](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#
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#
Originally Posted by Afrow UK View Post
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 🙂

Zinthose#edited
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#
Is it index 6 ? See, http://www.clarionopensource.com/Cla...hInterface.htm

I was recently fighting with something similar, ITypeLib 🙂
Zinthose#
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#
Just a warning... if anyone is playing around with this.. check your TaskManager.. I just found 23 instances of Excel running..... 😱

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#
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#
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#
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)