1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

COM Interface

Discussion in 'Support' started by Joe Caverly, Jul 18, 2013.

  1. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    Well over a year ago, I posted a suggestion to improve TCC with a COM Interface.

    As of this posting, my suggestion has 8 votes.

    There are few, if any, scripting languages that do not include a COM Interface.

    Plugins for TCC are great, but I cannot use them in another scripting language (PowerShell, VBSCript, AutoIt, etc.), nor can I call them from any programming language (Harbour, PowerBASIC, Visual Basic 6, etc.).

    I develop functions that I use personally into ActiveX COM DLLs. Only if I feel they would be useful to other TCC users do I make a TCC Plugin for those functions.

    ActiveX COM DLLs can be called from scripting languages, and programming languages. While I can write a wrapper for the COM Interface using <insert scripting language> and call it from TCC, it would be more efficient if TCC itself had the ability to directly call functions from a COM Interface.

    If you would like to see the addition of a COM Interface to TCC, please vote for this suggestion.

    jpsoft.uservoice.com/forums/94009-take-command/suggestions/2593250-com-interface

    Joe
     
  2. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,972
    Likes Received:
    30
    Joe, can you explain further how you envision it working? I know nothing about ActiveX and little about COM. Do you want all of TCC's power available in various scripting languages ... or for TCC to be able to use resources in DLLs not designed as plugins ... or both of those? I don't have a big picture.
     
  3. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    The link psoft.uservoice.com/forums/94009-take-command/suggestions/2593250-com-interface gives an example of what I envision.

    Let's say I wanted to use the COM Interface to Minimize All windows. Using AutoIt, I could do this as follows;

    Code:
    $oShell = ObjCreate("shell.application")
     
    $oShell.MinimizeAll
    If I wanted to do the same thing using VBScript;

    Code:
    dim objShell
     
    set objShell = CreateObject("shell.application")
    objshell.MinimizeAll
     
    set objShell = nothing
    In PowerShell;

    Code:
    $shellapp = New-Object -ComObject shell.application
    $shellapp.MinimizeAll()
    Thus, the function, contained in SHELL32.DLL, which has a COM Interface, can be called directly from a scripting/programming language that has a COM Interface. At present, TCC cannot call a function via the COM Interface from SHELL32.DLL. Yes, I am aware that TCC has the TASKBAR command to do this, but this was just an example.

    In my example at jpsoft.uservoice.com/forums/94009-take-command/suggestions/2593250-com-interface I show how I would call a function from a COM Interface that I have created.

    I can also call the functions in my COM Interface from Microsoft Excel (http://support.microsoft.com/kb/291392).

    I use Visual Basic 6.0 to create a COM Interface for my COM Objects and Automation Classes. Info on Creating a COM Interface using Visual C++ is available in the link.

    So, I would like TCC to be able to call the functions in .DLLs (such as SHELL32.DLL, which has a COM Interface, or in .DLLs that I create, which have a COM Interface), or in .EXEs that have a COM Interface (such as Microsoft Excel, Microsoft Word, which have a COM Interface, or in .EXEs that I create, which have a COM Interface), which are not designed as plugins, or standard DLLs.

    Joe
     
  4. Steve Fabian

    Joined:
    May 20, 2008
    Messages:
    3,520
    Likes Received:
    4
    I am not familiar with the COM interface, but it seems that TCC can already call functions in DLLs via the @CAPI or @WINAPI functions. Would a COM interface just be more convenient, and possibly less restricting of argument data type or argument count?
     
  5. Steve Fabian

    Joined:
    May 20, 2008
    Messages:
    3,520
    Likes Received:
    4
    Joe, you yourself posted a clever access to shell32.dll using @winapi to implement @shfolder in 4nt ...
     
  6. Charles Dye

    Charles Dye Super Moderator
    Staff Member

    Joined:
    May 20, 2008
    Messages:
    3,312
    Likes Received:
    39
    COM is a different, object-oriented API. (Microsoft promulgates APIs like Lindsay Lohan does tabloid headlines.)
     
  7. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    Well, if I want to read/write to a Microsoft Excel spreadsheet using PowerShell, I can access it via Excels COM Interface, thus;

    Code:
    $xl = New-Object -COM "Excel.Application"
    I can then open a workbook;

    Code:
    $wb = $xl.Workbooks.Open("C:\path\to\your.xlsx")
    and read/write to it via the COM Interface. I can do the same thing with a Microsoft Excel spreadsheet using AutoIt, VBScript, PowerBASIC, Visual Basic 6.0, PowerShell. I cannot do this with TCC.

    TCC has a lot of built-in functions. However, I would like to 'interface' to other applications, including ones that I have written. Since I build a COM Interface into EXEs and DLLs that I create, I can access my functions from PowerShell, AutoIt, VBScript, etc. I cannot do this from TCC.

    While I can create a plugin with all of my functions, that means putting my code in two locations; in my EXEs/DLLs that have a COM Interface, and in my plugins. I would prefer to put my code in one location, so that I can access it from PowerShell, AutoIt, VBScript, and TCC.

    Thus, that is why I could like TCC to be able to access EXEs/DLLs via their COM Interface.

    Joe
     
  8. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,972
    Likes Received:
    30
    Being able to access an Excel document doesn't excite me much. Is there a (more or less complete and more or less in one place) list of other of (Microsoft) classes whose properties and methods can be accessed via a COM interface?
     
  9. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    These are all listed on your system. Most products today offer a COM Interface. For example, I use Palm Desktop, which provides a COM Interface, so that I can access it from PowerShell, AutoIt, VBScript, etc.

    Microsoft has a program called OLEView, which comes with Visual Studio, the SDKs, Resource Tool Kits, or you can download it from Microsoft.

    Mine is located in C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin\OleView.Exe

    Use OLEView to discover the COM Interfaces of the applications installed on your system.

    Joe
     
  10. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,972
    Likes Received:
    30
    OLEView ... that's impressive, and daunting. Where in that maze of thousands of things would I find (for example) something related to whatever is happening when, in PowerShell, I
    Code:
    $shellapp = New-Object -ComObject shell.application
    In looking for something related to shell.application, I expanded ObjectClasses\AllObjects\ApplicationObject and immediately got a DataMystic purchase/license/registration details dialog. When I dismissed that dialog, I was left at what appeared to be a GUI TextPipeEngine filter tool (non-functional). What's that all about?
     
  11. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    I would say it is all about "Objects" ;)

    From the OLE/COM Object Viewer, look down the left-hand side for "Type Libraries"

    Expand "Type Libraries"

    Scroll down to "Microsoft Shell Controls And Automation"

    Right-click on "Microsoft Shell Controls And Automation", and select "View..."

    This will launch the ITypeLib Viewer

    Scroll down to "coclass Shell"

    Expand "coclass Shell", and keep expanding until you expose the "Methods"

    These are the Methods that are exposed through the COM Interface of SHELL32.DLL. You should see "MinimizeAll" as one of the "Methods" (functions).

    Click on each of the methods to see what, if any, arguments the Method takes. (Note that I call them functions, because that's what they are, but Microsoft says they are "Methods").

    After creating your own Automation Object with a COM Interface, you use Regsvr32 to load the component and register it with your system. You will then see it appear in the OLE/COM Object Viewer.

    You can then use PowerShell, VBScript, AutoIt, etc., to call the "Methods" of your target class. (coclass provides a listing of the supported interfaces for a component object.) I cannot use TCC to call the "Methods" of a target class, since TCC does not have a function to do this.

    Joe
     
  12. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,972
    Likes Received:
    30
    OK, I see. Thanks.

    On paper, it would seem a good idea to expose all that functionality to TCC users. But how much effort would that take? How much would it be used? I don't know.
     
  13. samintz

    samintz Scott Mintz

    Joined:
    May 20, 2008
    Messages:
    1,191
    Likes Received:
    11
    Any COM interface that uses a type library could be exposed in the same generic way that scripting languages access it. The COM interfaces without a type library would either need to be hard coded using the IDL files (if memory serves. It's been awhile since I did COM programming) or not supported.

    It should be relatively easy to code a plugin that does the "set thevalue = COM(Object, "Function", param1, param2, ...)" behavior.
     
  14. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    Way above my level of expertise, but a plugin like that would be quite useful to me.

    Joe
     
  15. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    Hmmm.... You got me thinking...

    Looking at early-binding seems a bit too complicated, but late-binding, although a bit slower, seems easier. Let me try something...

    ...well, ain't that something. I created a console app, passing in the name of the COM Object, and it creates the object.

    Looks like I am on my way. I will tinker with this for the next few days, and hopefully will have a plugin at the end of it.

    Thanks Scott. Not sure what you said that made it all clearer for me, but it got me thinking, and I just might be able to make my own solution.

    Joe
     
  16. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,972
    Likes Received:
    30
    I'm tempted to experiment a bit. I did a little reading and looked at a couple examples. The first question that came to mind is ... if you want to instantiate some COM object, don't you need to know a REFCLSID and a REFIID (or at least macros which represent them)? Example:
    Code:
    CLSID_ShellLink and IID_IShellLink
    Do you know if that's so, Joe. If that is the case, it would seem an app would have to be choosy about what it exposed to the user, maintain a database of those constants, and implement user-friendly names for the objects it exposed. And if all that's true, a totally general interface to all COM objects would seem impossible.
     
  17. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    If you are using early-binding, yes. That is why I am taking the late-binding approach. Here's the start of my Console app to access the COM Interface of an Object;

    Code:
    #COMPILE EXE "JLCCOM"
    #COMPILER PBWIN 8.05
    #DIM ALL
     
    FUNCTION PBMAIN () AS LONG
      DIM oUser AS DISPATCH
      DIM TheObject AS STRING
     
      TheObject = PARSE$(COMMAND$, 1)
     
      LET oUser = NEW DISPATCH IN TheObject
      IF ISOBJECT(oUser) THEN
        'Object was created
        MSGBOX COMMAND$ + " Object Created"
      ELSE
        MSGBOX "Could Not Create " + COMMAND$
        EXIT FUNCTION
      END IF
      LET oUser = NOTHING
    END FUNCTION
    Thus, as an example, from the command line, if I run;

    Code:
    jlccom.exe shell.application
    the Object gets created. If I run;

    Code:
    jlccom.exe shell.applicatio
    the Object does not get created.

    Joe
     
  18. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,972
    Likes Received:
    30
    I did find GUIDFromString and IIDFronString so maybe I can turn user-friendly names into the appropriate identifiers. I think COM is easier in VB. And I believe I'll have to do everything by hand, starting with CoInitialize.
     
  19. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    Yes, VB6 hides all of the complicated C-stuff, making development of ActiveX COM Objects very easy.

    PowerBASIC, which I use to develop plugins for TCC, is somewhere between VB6 and VC6, when it comes to working with COM Objects. PowerBASIC does the calls to CoInitialize and CoUninitialize under the hood.

    Joe
     
  20. Charles Dye

    Charles Dye Super Moderator
    Staff Member

    Joined:
    May 20, 2008
    Messages:
    3,312
    Likes Received:
    39

    I think that TCC.EXE might do the same -- Rex would know for certain.
     
  21. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,972
    Likes Received:
    30
    I think so too. But I could not catch TCC calling CoInitialize() with WinDbg. SYSUTILS\SHELLEX does not call CoInitialize(), but when I add a call to it, it returns S_FALSE (the COM library is already initialized on this thread).

    When I use SHELLEX with no explicit calls to CoAnything, I can catch, with WinDbg, two calls to CoUninitialize() (and none to CoInitialize()). I'm not sure what's going on.
     
  22. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,972
    Likes Received:
    30
    But I wasn't looking for CoInitializeEx() which TCC does call. CoInitializeEx() is also called (implicitly) twice when ShellExecuteEx() is used (accounting for the extra calls to CoUninitialize()).
     
  23. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    Here's what I have accomplished so far;

    Code:
    ::--------------------------------------------------------------------
    :: OBJECTCALL.BTM
    ::
    :: Call Methods from ActiveX (COM) Objects from the CLI
    ::
    :: TCC 15.01.52
    :: 2013/07/20
    :: Joe Caverly
    ::
    :: I am working on a TCC Plugin to accomplish this same task, and am
    ::  using this as an example of what I want to accomplish.
    ::
    :: The plugin version will be a function (@objectcall)
    ::  and a command (objectcall).
    ::
    :: TODO: Error checking of command line arguments, misc. stuff.
    ::--------------------------------------------------------------------
    @setlocal
    @echo off
     
    switch %#
    case 2
      gosub 2args
    case 3
      gosub 3args
    default
      echo USAGE: objectcall dispatch method argument
      echo Exple: objectcall jlcutils.clsmath ppp 6.59
      echo        objectcall shell.application minimizeall
      echo        objectcall shell.application filerun
      quit
    endswitch
     
    if exist objectcall.vbs del objectcall.vbs > nul
     
    do i = %start to %end
      echo %@line[%_batchname,%i] >> objectcall.vbs
    enddo
     
    cscript //nologo objectcall.vbs
     
    if exist objectcall.vbs del objectcall.vbs > nul
    endlocal
    quit
     
    :2args
    set start=%@eval[%_batchline+1]
    text > nul
    set dispatch = wscript.createobject("%1")
    wscript.echo dispatch.%2
    endtext
    set end=%@eval[%_batchline-3]
    return
     
    :3args
    set start=%@eval[%_batchline+1]
    text > nul
    set dispatch = wscript.createobject("%1")
    wscript.echo dispatch.%2("%3")
    endtext
    set end=%@eval[%_batchline-3]
    return
    Here is my (future) plugin code;

    Code:
    '---------------------------------------------------------------------
    ' JLCCOM will allow the calling of Methods from
    '  ActiveX DLLs (COM Objects) that I have created using VB6 (Visual
    '  Basic 6) via the CLI
    '
    ' Once I get this working, I will use this code to create a plugin for
    '  JPSoft's Take Command Console
    '
    #COMPILE EXE "JLCCOM"
    #COMPILER PBWIN 8.05
    #DIM ALL
     
    ' Requires LJ's Complete Console (LJ-CC) for PB/Win
    ' http://www.laurencejackson.com/LJ-CC/index.html
    #INCLUDE "C:\Users\jlc\Documents\powerbasic\lj-cc\lj-cc.bas"
     
    ' For debugging purposes
    MACRO VERBOSE = -1  ' 0 = ON
                        '-1 = OFF
     
    ' The program takes three arguments from the command line;
    '  Name of the DISPATCH
    '  Name of the METHOD
    '  Argument for the METHOD
    '
    '  Command line arguments (for testing) are;
    '  JLCUtils.clsMath,ppp,6.59
    '  |                |  |
    '  |                |  + strArgIn (vntArgIn)
    '  |                + strMethod
    '  + strObject
    '
    '
    ' The following MACRO works, and the desired results are returned.
    '
    MACRO ObjectCall = oUser.ppp(vntArgIn) TO vntResult
     
    ' The following MACRO does NOT work, as the strMethod text is not
    '  replaced with ppp that was entered via COMMAND$
    '
    'MACRO ObjectCall = oUser.strMethod(vntArgIn) TO vntResult
     
    FUNCTION PBMAIN () AS LONG
      DIM oUser AS DISPATCH
     
      DIM strObject AS STRING
      DIM strMethod AS STRING
      DIM strArgIn  AS STRING
      DIM strResult AS STRING
     
      DIM vntArgIn  AS VARIANT
      DIM vntMethod AS VARIANT
      DIM vntResult AS VARIANT
     
      strObject = PARSE$(COMMAND$, 1)
      strMethod = PARSE$(COMMAND$, 2)
      strArgIn  = PARSE$(COMMAND$, 3)
     
      vntArgIn = strArgIn
     
      LET oUser = NEW DISPATCH IN strObject
      IF ISOBJECT(oUser) THEN
        'Object was created
        #IF VERBOSE
          StdOutPrint strObject + " Object Created" + $CRLF
        #ENDIF
     
        'With the arguments passed, this line should be
        'OBJECT CALL oUser.ppp(vntArgIn) TO vntResult
        OBJECT CALL ObjectCall
        '
        ' ObjectCall is a MACRO, defined at line 36
        '
        #IF VERBOSE
          StdOutPrint "Error = " + STR$(ERR) + $CRLF
        #ENDIF
        strResult = LTRIM$(RTRIM$(STR$(VARIANT#(vntResult))))
        StdOutPrint strResult + $CRLF
      ELSE
        #IF VERBOSE
          StdOutPrint "Could Not Create " + strObject + $CRLF
        #ENDIF
        EXIT FUNCTION
      END IF
      LET oUser = NOTHING
    END FUNCTION
    I am having a bit of trouble with the MACRO command, as indicated in my code. I figure if I can do text substitution, I will not have to search for the INTERFACE METHOD in the DISPATCH (early-binding). I would much rather keep going on my late-binding approach.

    Joe
     
  24. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,972
    Likes Received:
    30
    I'm in uncharted waters here. I playing with the idea in C/C++. Maybe this will help you. Maybe you will help me. The code below works to verify that "Open" in a member and then invokes it. I can easily (and successfully) replace "Open" with "MinimizeAll" (changing dispparams.cArgs to 0) and the hard-coded "shell:desktop" wiith another (user-supplied) folder name.
    Code:
        WCHAR *szMember = L"Open";
        DISPID dispid;
        hr = pIShellDispatch->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
        if ( hr != S_OK ) return 3;
     
        VARIANT vArg, vResult;
        vArg.vt = VT_BSTR;
        vArg.bstrVal = L"shell:desktop";
        DISPPARAMS dispparams;
        dispparams.cArgs = 1;
        dispparams.rgvarg = &vArg;
        dispparams.cNamedArgs = 0;
     
        pIShellDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, &vResult, NULL, NULL);
    
     
  25. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,972
    Likes Received:
    30
    P.S. Member "WindowSwitcher" too ... I had never seen it ... pretty cool!
     
  26. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    Yepper, but that only works when the system has Windows Aero enabled. I have that disabled on my Windows Vista, saves resources.

    If I remember correctly, Windows Key-Tab is the combo for WindowSwitcher.

    Joe
     
  27. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    I am afraid that I do not "C/C++" very well. So, maybe this PowerBASIC code will help you. It shows how to create a class, with a method, that does not have a COM Interface, thus, it can only be used in that program;

    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "Win32API.inc"
     
    FUNCTION PBMAIN () AS LONG
      LOCAL JLCUtils AS iMath
      LOCAL ppk AS DOUBLE
     
      JLCUtils = CLASS "cJLCUtils"
     
      ppk = 6.59
     
      IF ISOBJECT(JLCUtils) THEN
        ? USING$("$#.## per kg is $#.## per lb", ppk, JLCUtils.ppp(ppk) )
      ELSE
        ? "Object was not created"
      END IF
    END FUNCTION
     
    CLASS cJLCUtils                            ' Name of our class
      INTERFACE iMath                      ' Name of our interface
      INHERIT IUNKNOWN                    ' What our interface inherits from
      METHOD ppp( BYVAL ppk AS DOUBLE) AS DOUBLE      ' Our method
        METHOD = ppk * .454                    ' Return the result of work
      END METHOD                          ' End of method
      END INTERFACE                        ' End of interface
    END CLASS                              ' End of class
    Many, many years ago, when I was learning Object-Oriented Programming, I first learned how to create classes, and work with them. After I understood that, I moved on to exposing the CLASS METHODS via a COM Interface.

    Joe
     
  28. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    Vince, here are links to working with COM Objects using the Windows API. I had these bookmarked, and I tried going through these a few years back, but way above my understanding, but it may help you.

    COM Tutorial #1: COM Object Memory
    http://www.jose.it-berater.org/smfforum/index.php?topic=2980.0

    COM Tutorial In Plain C
    http://www.jose.it-berater.org/smfforum/index.php?topic=3100.0

    Building Local Server
    http://www.jose.it-berater.org/smff...afa140823c193&topic=3100.0;prev_next=prev#new

    Joe
     
  29. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,972
    Likes Received:
    30
    Thanks, Joe. I'll check out the links. I think my point earlier was that once a user-named method checked out OK and I have a DISPID for it, I can call it with Invoke. Now I'm trying to figure out how to go from method name or DISPID to what types of arguments are expected by that method (I figure that's what type libs are all about; OLEViewer gets them). Even if the user knows what they are, a robust client would have to get them, typed correctly, into a DISPPARAMS struct in order for my strategy to work.
     
  30. Joe Caverly

    Joined:
    Aug 28, 2009
    Messages:
    680
    Likes Received:
    8
    After doing some (okay, quite a bit) of reading, I came upon a COM DLL called TLBINF32.DLL, which is a TypeLib Information library.

    This file came with my Visual Studio 6.0, specifically, Visual Basic 6.0. The help file starts off with;

    A search of the web revealed the dumpTypeLib.vbs visual basic script file, which uses TLBINF32.DLL, and does as it says.

    This seems to be part of the solution for calling any Method in a COM object. Not sure if the TLBINF32.DLL file is installed on every Microsoft Windows system, or, if not, if TLBINF32.DLL can legally be installed on any system.

    Joe
     

Share This Page