Winamp & Shoutcast Forums

Winamp & Shoutcast Forums (http://forums.winamp.com/index.php)
-   NSIS Discussion (http://forums.winamp.com/forumdisplay.php?f=65)
-   -   Playing with COM (http://forums.winamp.com/showthread.php?t=321811)

Zinthose 19th August 2010 19:12

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?

PHP Code:

    /*
    !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=$


Animaether 19th August 2010 19:24

Quote:

Originally Posted by Zinthose (Post 2689904)
My code is choking at GetIDsOfNames... Can anyone add some insight?

PHP Code:

    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 19th August 2010 20:24

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 20:32

Quote:

Originally Posted by Afrow UK (Post 2689927)
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;
Quote:

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 20:40

Aight... Using the VTable index to lookup the interfaces methods I have now updated with the following..
PHP Code:

    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 20:48

Is it index 6 ? See, http://www.clarionopensource.com/Cla...hInterface.htm

I was recently fighting with something similar, ITypeLib :)

Zinthose 19th August 2010 22:12

Woot! It was the BSTR!
PHP Code:

    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 22:23

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.
PHP Code:

    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 22:58

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 19th August 2010 23:56

Good idea!!

Here is what I thew together.. needs more optimizations but it's a good start..
PHP Code:

    ## 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 17:27

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)


All times are GMT. The time now is 18:03.

Copyright © 1999 - 2010 Nullsoft. All Rights Reserved.