VBScript OLE Automation from a C Application

Discussion in 'C Programming' started by Joe Caverly, Jul 8, 2003.

  1. Joe Caverly

    Joe Caverly Guest

    Hi,
    I'm using Visual C++ 32-bit Professional Edition 5.0

    Using Microsoft Knowledge Base Article 181473 as a basis, I'm trying
    to transform this VB Code;

    Dim sc As Object
    Dim code As String
    Set sc = CreateObject("ScriptControl")
    sc.Language = "VBScript"
    On Error Resume Next
    code = "Function Square(x)" & vbCrLf _
    & "Square = x * x" & vbCrLf _
    & "End Function"
    sc.AddCode code
    If Err Then
    MsgBox "Syntax Error", vbCritical
    End If
    result = sc.Run("Square", 12.34)
    MsgBox result

    into plain C code, not C++. Here's what I've done so far;

    #include <stdio.h>
    #include <windows.h>

    void main(void) {
    IDispatch *pDisp; // Main IDispatch pointer.
    unsigned short *ucPtr; // Temporary variable to hold names.
    DISPID dispID; // Temporary variable to hold DISPIDs.
    CLSID clsid; // Holds CLSID of server after CLSIDFromProgID.
    HRESULT hr; // General error/result holder.
    char buf[8192]; // Generic buffer for output.

    // IDispatch::Invoke() parameters...
    DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
    VARIANT parm1;
    DISPID dispidNamed = DISPID_PROPERTYPUT;


    // Initialize OLE Libraries.
    OleInitialize(NULL);
    {
    // Get CLSID for ScriptControl Application from registry.
    hr = CLSIDFromProgID(L"ScriptControl", &clsid);
    if(FAILED(hr)) {
    MessageBox(NULL, "ScriptControl not registered.", "Error",
    MB_SETFOREGROUND);
    return;
    }
    // Start Scriptcontrol and get its IDispatch pointer.
    hr = CoCreateInstance(&clsid, NULL,
    CLSCTX_LOCAL_SERVER|CLSCTX_INPROC_SERVER,
    &IID_IDispatch, (void **)&pDisp);
    if(FAILED(hr)) {
    MessageBox(NULL, "Couldn't start ScriptControl", "Error",
    MB_SETFOREGROUND);
    return;
    }

    // Get the 'Language' property's DISPID.
    ucPtr = L"Language";
    pDisp->lpVtbl->GetIDsOfNames(pDisp, &IID_NULL, &ucPtr, 1,
    LOCALE_USER_DEFAULT, &dispID);

    sprintf(buf, "DISPID for 'Language' property = 0x%08lx",
    dispID);
    MessageBox(NULL, buf, "Debug Notice", MB_SETFOREGROUND);

    // Initiate parameters to set Language property to VBScript.
    VariantInit(&parm1);
    parm1.vt = VT_BSTR;
    parm1.bstrVal = SysAllocString( OLESTR("VBScript"));

    // One argument.
    dispParams.cArgs = 1;
    dispParams.rgvarg = &parm1;

    // Handle special-case for property-puts!
    dispParams.cNamedArgs = 1;
    dispParams.rgdispidNamedArgs = &dispidNamed;

    // Set 'Language' property to VBScript.
    hr = pDisp->lpVtbl->Invoke(pDisp,
    dispID, &IID_NULL, LOCALE_SYSTEM_DEFAULT,
    DISPATCH_PROPERTYPUT | DISPATCH_METHOD,
    &dispParams, NULL, NULL, NULL
    );
    if(FAILED(hr)) {
    sprintf(buf, "IDispatch::Invoke() failed with %08lx", hr);
    MessageBox(NULL, buf, "Debug Notice", MB_SETFOREGROUND);
    }

    // All done.
    MessageBox(NULL, "done.", "Notice", MB_SETFOREGROUND);
    }
    // Uninitialize OLE Libraries.
    OleUninitialize();

    }

    An error is raised when I attempt to set the 'Language' property to
    VBScript, that is, "IDispatch::Invoke() failed with 80020003"

    TIA for your assistance.

    Joe
     
    Joe Caverly, Jul 8, 2003
    #1
    1. Advertising

  2. Joe Caverly

    -berlin.de Guest

    Joe Caverly <> wrote:
    > Hi,
    > I'm using Visual C++ 32-bit Professional Edition 5.0


    > Using Microsoft Knowledge Base Article 181473 as a basis, I'm trying
    > to transform this VB Code;


    > Dim sc As Object
    > Dim code As String
    > Set sc = CreateObject("ScriptControl")
    > sc.Language = "VBScript"
    > On Error Resume Next
    > code = "Function Square(x)" & vbCrLf _
    > & "Square = x * x" & vbCrLf _
    > & "End Function"
    > sc.AddCode code
    > If Err Then
    > MsgBox "Syntax Error", vbCritical
    > End If
    > result = sc.Run("Square", 12.34)
    > MsgBox result


    > into plain C code, not C++. Here's what I've done so far;


    Your program contains that many system specific function calls,
    typedefs and probably macros that it's basically impossible to
    figure out what might be the problem. Even worse, the question
    is compelete off-topic here, because it is about something
    absolutely system-specific. All you can expect from clc is that
    people point out the C errors in your program because the topic
    here is standard C, not some vendor-specific extensions. You
    probably would get more helpful answers for your problem
    from a newsgroup with microsoft somewhere in its name.

    > #include <stdio.h>
    > #include <windows.h>


    Non-standard header...

    > void main(void) {


    int main( void )

    > IDispatch *pDisp; // Main IDispatch pointer.
    > unsigned short *ucPtr; // Temporary variable to hold names.
    > DISPID dispID; // Temporary variable to hold DISPIDs.
    > CLSID clsid; // Holds CLSID of server after CLSIDFromProgID.
    > HRESULT hr; // General error/result holder.
    > char buf[8192]; // Generic buffer for output.


    > // IDispatch::Invoke() parameters...
    > DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
    > VARIANT parm1;
    > DISPID dispidNamed = DISPID_PROPERTYPUT;


    All types execpt 'unsigned short' and 'char' are non-standard C
    and you don't tell what they actually mean...

    > // Initialize OLE Libraries.
    > OleInitialize(NULL);
    > {
    > // Get CLSID for ScriptControl Application from registry.
    > hr = CLSIDFromProgID(L"ScriptControl", &clsid);


    What is that 'L"ScriptControl"' supposed to mean? Unless 'L' is
    a macro for a literal string your compiler should complain loudly.

    > if(FAILED(hr)) {
    > MessageBox(NULL, "ScriptControl not registered.", "Error",
    > MB_SETFOREGROUND);
    > return;


    Since main() must be an integer returning function you need something
    like "return 0;" or "return EXIT_FAILURE;" (this would require
    inclusion of <stdlib.h>) here.

    > }
    > // Start Scriptcontrol and get its IDispatch pointer.
    > hr = CoCreateInstance(&clsid, NULL,
    > CLSCTX_LOCAL_SERVER|CLSCTX_INPROC_SERVER,
    > &IID_IDispatch, (void **)&pDisp);


    Where did you define 'IID_IDispatch'? It definitely shouldn't be
    defined in a header file (the only remotely likely candidate being
    the non-standard <windows.h> header and I don't think that people
    at Microsoft would be that stupid to define variables in header
    files) and you never defined it, but you try to take its address...

    > if(FAILED(hr)) {
    > MessageBox(NULL, "Couldn't start ScriptControl", "Error",
    > MB_SETFOREGROUND);
    > return;
    > }


    > // Get the 'Language' property's DISPID.
    > ucPtr = L"Language";


    Again this strange 'L"Language"' stuff. And even if 'L' should be a
    macro for a literal string you would need 'ucPtr' to be of type
    'const char *' instead of 'unsigned short *'.

    > pDisp->lpVtbl->GetIDsOfNames(pDisp, &IID_NULL, &ucPtr, 1,
    > LOCALE_USER_DEFAULT, &dispID);


    'IID_NULL' has never been defined.

    > sprintf(buf, "DISPID for 'Language' property = 0x%08lx",
    > dispID);


    This assumes that the DISPID type is an unsigned long, which may be
    correct but is impossible to tell.

    > MessageBox(NULL, buf, "Debug Notice", MB_SETFOREGROUND);


    > // Initiate parameters to set Language property to VBScript.
    > VariantInit(&parm1);
    > parm1.vt = VT_BSTR;
    > parm1.bstrVal = SysAllocString( OLESTR("VBScript"));


    If this is a memory allocation in disguise, shouldn't you deallocate
    the memory somewhere when you don't need it anymore?

    > // One argument.
    > dispParams.cArgs = 1;
    > dispParams.rgvarg = &parm1;


    > // Handle special-case for property-puts!
    > dispParams.cNamedArgs = 1;
    > dispParams.rgdispidNamedArgs = &dispidNamed;


    > // Set 'Language' property to VBScript.
    > hr = pDisp->lpVtbl->Invoke(pDisp,
    > dispID, &IID_NULL, LOCALE_SYSTEM_DEFAULT,
    > DISPATCH_PROPERTYPUT | DISPATCH_METHOD,
    > &dispParams, NULL, NULL, NULL
    > );
    > if(FAILED(hr)) {
    > sprintf(buf, "IDispatch::Invoke() failed with %08lx", hr);


    This assumes that the HRESULT type is an unsigned long, how do you
    know?

    > MessageBox(NULL, buf, "Debug Notice", MB_SETFOREGROUND);
    > }


    > // All done.
    > MessageBox(NULL, "done.", "Notice", MB_SETFOREGROUND);
    > }
    > // Uninitialize OLE Libraries.
    > OleUninitialize();


    Missing return value from main().

    > }


    > An error is raised when I attempt to set the 'Language' property to
    > VBScript, that is, "IDispatch::Invoke() failed with 80020003"


    How did you manage to get the above "program" to compile? I can
    hardly believe it...
    Regards, Jens
    --
    _ _____ _____
    | ||_ _||_ _| -berlin.de
    _ | | | | | |
    | |_| | | | | | http://www.physik.fu-berlin.de/~toerring
    \___/ens|_|homs|_|oerring
     
    -berlin.de, Jul 8, 2003
    #2
    1. Advertising

  3. -berlin.de wrote:

    > Joe Caverly <> wrote:
    >>
    >> // Get CLSID for ScriptControl Application from registry.
    >> hr = CLSIDFromProgID(L"ScriptControl", &clsid);

    >
    > What is that 'L"ScriptControl"' supposed to mean?


    It's a wide string literal. Perfectly standard C.

    <snip>

    --
    Richard Heathfield :
    "Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
    K&R answers, C books, etc: http://users.powernet.co.uk/eton
     
    Richard Heathfield, Jul 8, 2003
    #3
  4. Joe Caverly

    -berlin.de Guest

    Richard Heathfield <> wrote:
    > -berlin.de wrote:


    >> Joe Caverly <> wrote:
    >>>
    >>> // Get CLSID for ScriptControl Application from registry.
    >>> hr = CLSIDFromProgID(L"ScriptControl", &clsid);

    >>
    >> What is that 'L"ScriptControl"' supposed to mean?


    > It's a wide string literal. Perfectly standard C.


    Thanks for pointing this out - I never had to deal with wchar_t's,
    so I didn't know about this (but for sake of consistency I would
    have expected to have the modifier *after* the string like in 3L).

    Regards, Jens
    --
    _ _____ _____
    | ||_ _||_ _| -berlin.de
    _ | | | | | |
    | |_| | | | | | http://www.physik.fu-berlin.de/~toerring
    \___/ens|_|homs|_|oerring
     
    -berlin.de, Jul 9, 2003
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Greg Howard
    Replies:
    1
    Views:
    3,297
    Matt Garrish
    Jul 2, 2004
  2. Kosic

    OLE Automation by Javascript

    Kosic, Oct 31, 2003, in forum: ASP .Net
    Replies:
    2
    Views:
    3,977
    Tim Burda
    Nov 21, 2003
  3. Patrick.O.Ige

    Ole ole

    Patrick.O.Ige, Jul 16, 2006, in forum: ASP .Net
    Replies:
    0
    Views:
    508
    Patrick.O.Ige
    Jul 16, 2006
  4. Drew Pihera
    Replies:
    0
    Views:
    655
    Drew Pihera
    Feb 4, 2004
  5. Lance Hoffmeyer
    Replies:
    0
    Views:
    251
    Lance Hoffmeyer
    Nov 17, 2003
Loading...

Share This Page