SHARE
Facebook X Pinterest WhatsApp

Adding Scripting Support to an Application

Environment: VC6 SP5, Windows 98 +, Microsoft Windows Script Control, Windows 2000 SP3 Introduction Sometimes, there is no need to implement full scripting support as explained in the articles about ActiveX script hosting. The ScriptControlMacro program shows the easy way to do it using Microsoft Script Control. There are also other interesting techniques in the […]

Written By
thumbnail
CodeGuru Staff
CodeGuru Staff
Jun 23, 2003
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Environment: VC6 SP5, Windows 98 +, Microsoft Windows Script Control, Windows 2000 SP3

Introduction

Sometimes, there is no need to implement full scripting support as explained in the articles about ActiveX script hosting. The ScriptControlMacro program shows the easy way to do it using Microsoft Script Control. There are also other interesting techniques in the application:


  • How to allow only one application instance and find its main window using a File Mapping

  • How to use English resources that are built into MFC4x.DLL and prevent the use of MFC4xLOC.DLL

  • How to store and load binary registry data using MFC

  • How to restore the last size and position of the application windows

  • How to use different fonts in the class derived from CEditView

  • How to show recent files list in the menu only when it is not empty

  • Reset newly created (untitled) documents counter

  • How to catch OLE exceptions and show error messages with extended information

Before You Start

This article assumes you’re familiar with COM, ActiveX controls, OLE Automation, and how to use them in MFC. There is a lot of corresponding material about these technologies; so, if you are not, read and come back later.

Basic Steps


  1. Create a new MFC application, including support for ActiveX controls.
  2. Create a dispatch classes from the Script Control type-library using ClassWizard.
  3. ClassWizard will generate header and implementation files for Script Control interfaces:

    // Machine generated IDispatch wrapper class(es) created with
    // ClassWizard
    ///////////////////////////////////////////////////////////////
    // IScriptControl wrapper class
    class IScriptControl : public COleDispatchDriver
    {
    // Operations
    public:
      void SetLanguage(LPCTSTR lpszNewValue);
      void SetSitehWnd(HWND hWnd);
      LPDISPATCH GetError();
      void AddObject(LPCTSTR Name, LPDISPATCH Object,
                     BOOL AddMembers);
      void AddCode(LPCTSTR Code);
    };
    // Machine generated IDispatch wrapper class(es) created with
    // ClassWizard
    #include “stdafx.h”
    #include “MSScriptControl.h”
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    ///////////////////////////////////////////////////////////////
    // IScriptControl operations
    void IScriptControl::SetLanguage(LPCTSTR lpszNewValue)
    {
      static BYTE parms[] =
        VTS_BSTR;
      InvokeHelper(0x5dc, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL,
                   parms, lpszNewValue);
    }
    void IScriptControl::SetSitehWnd(HWND hWnd)
    {
      static BYTE parms[] =
        VTS_I4;
      InvokeHelper(0x5de, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL,
                   parms, hWnd);
    }
    LPDISPATCH IScriptControl::GetError()
    {
      LPDISPATCH result;
      InvokeHelper(0x5e3, DISPATCH_PROPERTYGET, VT_DISPATCH,
                         (void*)&result, NULL);
      return result;
    }
    void IScriptControl::AddObject(LPCTSTR Name, LPDISPATCH Object,
                                   BOOL AddMembers)
    {
      static BYTE parms[] =
        VTS_BSTR VTS_DISPATCH VTS_BOOL;
      InvokeHelper(0x9c4, DISPATCH_METHOD, VT_EMPTY, NULL, parms,
         Name, Object, AddMembers);
    }
    void IScriptControl::AddCode(LPCTSTR Code)
    {
      static BYTE parms[] =
        VTS_BSTR;
      InvokeHelper(0x7d0, DISPATCH_METHOD, VT_EMPTY, NULL, parms,
                   Code);
    }
    

  4. Remove unneeded IDispatch wrapper methods from classes.

  5. If you want to add your own functions to the scripts, add an Automation class using ClassWizard.

    ClassWizard will generate header and implementation files for the IDispatch interface:

    // ScriptControlMacroDispatch.h : interface of the
    // CScriptControlMacroDispatch class
    //
    ///////////////////////////////////////////////////////////////
    #if !defined(AFX_SCRIPTCONTROLMACRODISPATCH_H__FB55B5AF_00E5_
        47F5_B176_214B2C7BF19A__INCLUDED_)
    #define AFX_SCRIPTCONTROLMACRODISPATCH_H__FB55B5AF_00E5_47F5_
            B176_214B2C7BF19A__INCLUDED_
    #if _MSC_VER > 1000
    #pragma once
    #endif    // _MSC_VER > 1000
    ///////////////////////////////////////////////////////////////
    // CScriptControlMacroDispatch command target
    class CScriptControlMacroDispatch : public CCmdTarget
    {
      DECLARE_DYNCREATE(CScriptControlMacroDispatch)
      CScriptControlMacroDispatch();    // protected constructor
                                        // used by dynamic creation
    // Overrides
      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CScriptControlMacroDispatch)
      //}}AFX_VIRTUAL
    // Implementation
    protected:
      //friend class CScriptControlMacroView;
      // Generated message map functions
      //{{AFX_MSG(CScriptControlMacroDispatch)
        // NOTE – the ClassWizard will add and remove member
        //        functions here.
      //}}AFX_MSG
      DECLARE_MESSAGE_MAP()
      // Generated OLE dispatch map functions
      //{{AFX_DISPATCH(CScriptControlMacroDispatch)
      afx_msg void Test1();
      afx_msg void Test2();
      //}}AFX_DISPATCH
      DECLARE_DISPATCH_MAP()
      DECLARE_INTERFACE_MAP()
    };
    extern const IID IID_IScriptControlMacroDispatch;
    ///////////////////////////////////////////////////////////////
    //{{AFX_INSERT_LOCATION}}
    // Microsoft Visual C++ will insert additional declarations
    // immediately before the previous line.
    #endif // !defined(AFX_SCRIPTCONTROLMACRODISPATCH_H__FB55B5AF_
           //   00E5_47F5_B176_214B2C7BF19A__INCLUDED_)
    // ScriptControlMacroDispatch.cpp : implementation of the
    // CScriptControlMacroDispatch class
    //
    #include “stdafx.h”
    #include “ScriptControlMacroDispatch.h”
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    ///////////////////////////////////////////////////////////////
    // CScriptControlMacroDispatch
    IMPLEMENT_DYNCREATE(CScriptControlMacroDispatch, CCmdTarget)
    CScriptControlMacroDispatch::CScriptControlMacroDispatch()
    {
      EnableAutomation();
    }
    BEGIN_MESSAGE_MAP(CScriptControlMacroDispatch, CCmdTarget)
      //{{AFX_MSG_MAP(CScriptControlMacroDispatch)
        // NOTE – the ClassWizard will add and remove mapping
        // macros here.
      //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    BEGIN_DISPATCH_MAP(CScriptControlMacroDispatch, CCmdTarget)
      //{{AFX_DISPATCH_MAP(CScriptControlMacroDispatch)
      DISP_FUNCTION(CScriptControlMacroDispatch, “Test1”, Test1,
                    VT_EMPTY, VTS_NONE)
      DISP_FUNCTION(CScriptControlMacroDispatch, “Test2”, Test2,
                    VT_EMPTY, VTS_NONE)
      //}}AFX_DISPATCH_MAP
    END_DISPATCH_MAP()
    // Note: we add support for IID_IScriptControlMacroDispatch
    // to support typesafe binding from VBA. This IID must match
    // the GUID that is attached to the dispinterface in the
    // .ODL file.
    // {69AA5686-41AF-4CD9-AEAE-9DB88130E7C1}
    const IID IID_IScriptControlMacroDispatch =
    {0x69AA5686, 0x41AF, 0x4CD9, {0xAE, 0xAE, 0x9D, 0xB8, 0x81,
                 0x30, 0xE7, 0xC1}};
    BEGIN_INTERFACE_MAP(CScriptControlMacroDispatch, CCmdTarget)
      INTERFACE_PART(CScriptControlMacroDispatch,
                         IID_IScriptControlMacroDispatch, Dispatch)
    END_INTERFACE_MAP()
    ///////////////////////////////////////////////////////////////
    // CScriptControlMacroDispatch message handlers
    void CScriptControlMacroDispatch::Test1()
    {
      // TODO: Add your dispatch handler code here
      AfxMessageBox(CString(_T(“\””)) + GetDispatchMap()->
                lpEntries->lpszName + _T(“\” method call of the
                \””) + RUNTIME_CLASS(CScriptControlMacroDispatch)->
                m_lpszClassName + _T(“\” class”), MB_ICONASTERISK);
    }
    void CScriptControlMacroDispatch::Test2()
    {
      // TODO: Add your dispatch handler code here
      AfxMessageBox(CString(_T(“\””)) + GetDispatchMap()->
                    lpEntries[1].lpszName + _T(“\” method call
                    of the \””) + RUNTIME_CLASS(
                       CScriptControlMacroDispatch)->
                       m_lpszClassName + _T(“\” class”),
                       MB_ICONASTERISK);
    }
    

  6. Several customizations have been done in the generated code:

    1. unnecessary declarations and code have been removed;

    2. the application object variable was made globally accessible: extern CScriptControlMacroApp theApp;

    3. an MFC “hidden” function declaration was added: CString AFXAPI AfxStringFromCLSID( REFCLSID );

    4. the ID of the interface that is mapped to the CScriptControlMacroDispatch class was made globally accessible for using in AfxStringFromCLSID function: extern const IID IID_IScriptControlMacroDispatch;

  7. To easily support Unicode in all MFC applications, the following customization has been done in the AFX.H header file:
  8. ///////////////////////////////////////////////////////////////
    // Win32 libraries
    // Start of customization
    #if !defined(_CONSOLE) && defined(_UNICODE)
      #pragma comment(linker, “/entry:wWinMainCRTStartup”)
    #endif
    // End of customization
    

  9. To use the _WIN32_WINDOWS=0x400 preprocessor definition in all MFC applications, the following customization has been done in the AFXV_W32.H header file:
  10. #ifndef ALL_WARNINGS
    #pragma warning(disable: 4201)    // winnt.h uses nameless
                                      // structs
    #endif
    // Start of customization
    #ifndef _WIN32_WINDOWS
    // End of customization
    #define _WIN32_WINDOWS 0x0500
    // Start of customization
    #endif
    // End of customization
    


References

Information on the Script Control can be found at the MSDN Scripting Site.

Additional information can be found in the following articles in the Microsoft Knowledge Base:

184739 INFO: Where to Obtain the Script Control

184977 FIX: ScriptControl Reports Invalid Language for VBScript in MFC

165967 PRB: Script Error Occurs When Referencing Non-variant Array

229669 HOWTO: Call Run() Method of the Microsoft Script Control in C++

More information:

Visual Programmer: Add Scripting to Your Apps with Microsoft ScriptControl – MSDN Magazine, June 2000

Downloads



Download demo project – 10 Kb


Download source – 29 Kb

Recommended for you...

Introduction to Web Components API
Tariq Siddiqui
Jul 13, 2022
From SOAP to REST to GraphQL: API Deep Dive
Joydip Kanjilal
Jun 14, 2022
Implement Swagger In ASP.NET Web API
Tapas Pal
Nov 14, 2021
Why Should I Move to the Cloud?
Zaher Talab
Oct 15, 2021
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.