如何使我们的COM对象可以被脚本语言调用

2024-02-28 03:08
文章标签 对象 调用 com 脚本语言

本文主要是介绍如何使我们的COM对象可以被脚本语言调用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

COM初探(五)——从IDispatch接口继承

(一)目标
本文用一个简单的例子来讲述如何使我们的COM对象可以被脚本语言调用。

(二)IDL文件
为了在脚本语言环境中使用COM组件,COM规范规定要在脚本语言环境使用的COM必须实现IDispatch接口。
下面我们定义接口ITimeBeijing,请注意这个文件和我们以前的文件的不同点:

import "oaidl.idl";
import "ocidl.idl";

[
 uuid(30002489-29D8-4c48-9B1F-D6660A818E7B),
 object,
 dual,//这个标识说明定义的是双接口
 pointer_default(unique)
]
interface ITimeBeijing : IDispatch//必须从IDispatch接口派生
{
 [id(1)] HRESULT GetHour([out, retval] int * hour);//每个函数前都有id号,便于调用
 [id(2)] HRESULT GetMinute([out, retval] int * min);
 [id(3)] HRESULT GetSecond([out, retval] int * sec);
};

[
 uuid(8AE3C9BA-CEE9-4d33-A4C1-DB4FBFBB9A43),
 version(1.0),
]
library TimeBeijingLib
{
 importlib("stdole32.tlb");
 importlib("stdole2.tlb");

 [
  uuid(ECE8BF15-11FB-45a4-90A1-1788DDAB31AC),
 ]
 coclass TimeBeijingClass//com类
 {
  [default] interface ITimeBeijing;
 };
};

(三)建立COM类TimeBeijingClass
请注意和以前的不同点。
这里的类需要实现3个接口:IUnknown, IDispatch和ITimeBeijing。

// TimeBeijingClass.h: interface for the TimeBeijingClass class.
//
//

#if !defined(AFX_TIMEBEIJINGCLASS_H__E9800212_16E2_4BE3_B646_420DC02F50AE__INCLUDED_)
#define AFX_TIMEBEIJINGCLASS_H__E9800212_16E2_4BE3_B646_420DC02F50AE__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "TimeBeijing.h"

class TimeBeijingClass : public ITimeBeijing 
{
public:
 TimeBeijingClass();
 ~TimeBeijingClass();

public:
 // IUnknown
 STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
 STDMETHOD_(ULONG, AddRef)();
 STDMETHOD_(ULONG, Release)();

 // IDispatch
 STDMETHOD(GetTypeInfoCount)(UINT * pit);
 STDMETHOD(GetTypeInfo)(UINT it,LCID lcid,ITypeInfo **ppti);
 STDMETHOD(GetIDsOfNames)(REFIID riid,
  OLECHAR ** pNames,
  UINT nNames,
  LCID lcid,
  DISPID * pdispids);

 STDMETHOD(Invoke)(DISPID id,
  REFIID riid,
  LCID lcid,
  WORD wFlags,
  DISPPARAMS *pd,
  VARIANT * pVarResult,
  EXCEPINFO * pe,
  UINT *pu);

 // ITimeBeijing
 STDMETHOD(GetHour)(int * hour);
 STDMETHOD(GetMinute)(int * min);
 STDMETHOD(GetSecond)(int * sec);

private:
 LONG m_cRef;
};

#endif // !defined(AFX_TIMEBEIJINGCLASS_H__E9800212_16E2_4BE3_B646_420DC02F50AE__INCLUDED_)


// TimeBeijingClass.cpp: implementation of the TimeBeijingClass class.
//
//

#include "TimeBeijingClass.h"
#include "stdio.h"
#include <time.h>
#include "TimeBeijing_i.c"
//
// Construction/Destruction
//

TimeBeijingClass::TimeBeijingClass()
{
 printf("TimeBeijingClass - Constructor/n");
 m_cRef = 0;
}

TimeBeijingClass::~TimeBeijingClass()
{
 printf("TimeBeijingClass - Destructor/n");
}

// IUnknown
STDMETHODIMP TimeBeijingClass::QueryInterface(REFIID riid, void **ppv)
{
 printf("TimeBeijingClass - QueryInterface/n");
 if(riid == IID_ITimeBeijing)
  *ppv = static_cast<ITimeBeijing *>(this);
 else if(riid == IID_IUnknown)
  *ppv = static_cast<ITimeBeijing *>(this);
 else if(riid == IID_IDispatch)
  *ppv = static_cast<IDispatch *>(this);
 else {
  *ppv = 0;
  return E_NOINTERFACE;
 }
 
 reinterpret_cast<IUnknown *>(*ppv)->AddRef();
 return S_OK;
}

STDMETHODIMP_(ULONG) TimeBeijingClass::AddRef()
{
 printf("TimeBeijingClass - AddRef/n");
 return ++m_cRef;
}

STDMETHODIMP_(ULONG) TimeBeijingClass::Release()
{
 printf("TimeBeijingClass - Release/n");
 ULONG res = --m_cRef; 
 if(res == 0)
  delete this;
 return res;
}

// IDispatch
//此函数是重点,请结合程序并参考msdn理解其中参数的含义
STDMETHODIMP TimeBeijingClass::Invoke(DISPID id, REFIID riid, LCID lcid,
           WORD wFlags, DISPPARAMS *pd,
           VARIANT * pVarResult, EXCEPINFO * pe, UINT *pu)
{
 if(riid == IID_ITimeBeijing)
    { 
  if(1 == id)
   return GetHour(&pVarResult->intVal);
  else if (2 == id)
   return GetMinute(&pVarResult->intVal);
  else if (3 == id)
   return GetSecond(&pVarResult->intVal);
  else
   return E_FAIL;
 }
 else
  return E_NOINTERFACE;

}

//为了简化程序,下面的接口函数都没有实现
STDMETHODIMP TimeBeijingClass::GetIDsOfNames(REFIID riid, OLECHAR ** pNames,
            UINT nNames, LCID lcid, DISPID * pdispids)
{
 return E_NOTIMPL;
}

STDMETHODIMP TimeBeijingClass::GetTypeInfo(UINT it,LCID lcid,ITypeInfo **ppti)
{
 return E_NOTIMPL;
}

STDMETHODIMP TimeBeijingClass::GetTypeInfoCount(UINT * pit)
{
 return E_NOTIMPL;
}

// ITimeBeijing
STDMETHODIMP TimeBeijingClass::GetHour(int * hour)
{
 printf("TimeBeijingClass - GetHour/n");
 
 time_t ltime;
 struct tm *today;
 
 time(&ltime);
 today = localtime(&ltime);
 
 *hour = today->tm_hour;
 
 return S_OK;
}

STDMETHODIMP TimeBeijingClass::GetMinute(int * min)
{
 printf("TimeBeijingClass - GetMinute/n");
 
 time_t ltime;
 struct tm *today;
 
 time(&ltime);
 today = localtime(&ltime);

 *min = today->tm_min;
 
 return S_OK;
}

STDMETHODIMP TimeBeijingClass::GetSecond(int * sec)
{
 printf("TimeBeijingClass - GetMinute/n");
 
 time_t ltime;
 struct tm *today;
 
 time(&ltime);
 today = localtime(&ltime);
 
 *sec = today->tm_sec;
 
 return S_OK;
}

(四)类工厂文件(微小的变化:QueryInterface)
// TimeBeijingClassFactory.h: interface for the TimeBeijingClassFactory class.
//
//

#if !defined(AFX_TIMEBEIJINGCLASSFACTORY_H__AB2637DD_45D2_48CD_BAD8_46E372268A8C__INCLUDED_)
#define AFX_TIMEBEIJINGCLASSFACTORY_H__AB2637DD_45D2_48CD_BAD8_46E372268A8C__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <unknwn.h>

class TimeBeijingClassFactory : public IClassFactory 
{
public:
 TimeBeijingClassFactory();
 ~TimeBeijingClassFactory();

public:
 //IUnknow Method
 STDMETHODIMP QueryInterface(REFIID,void**);
 STDMETHODIMP_(ULONG) AddRef();
 STDMETHODIMP_(ULONG) Release();
 
 //IClassFactory Method
 STDMETHODIMP CreateInstance(IUnknown * ,REFIID ,void **);
 STDMETHODIMP LockServer(BOOL fLock);
 
private:
 LONG m_cRef;

};

#endif // !defined(AFX_TIMEBEIJINGCLASSFACTORY_H__AB2637DD_45D2_48CD_BAD8_46E372268A8C__INCLUDED_)


// TimeBeijingClassFactory.cpp: implementation of the TimeBeijingClassFactory class.
//
//

#include "TimeBeijingClassFactory.h"
#include "stdio.h"
#include "TimeBeijingClass.h"
//
// Construction/Destruction
//

extern LONG g_cObjectAndLocks;

TimeBeijingClassFactory::TimeBeijingClassFactory()
{
 printf("TimeBeijingClassFactory - constructor/n");
 m_cRef = 0;
}

TimeBeijingClassFactory::~TimeBeijingClassFactory()
{
 printf("TimeBeijingClassFactory - destructor/n");
}

STDMETHODIMP_(ULONG) TimeBeijingClassFactory::AddRef(void)
{
 printf("TimeBeijingClassFactory - AddRef/n");
 return InterlockedIncrement(&m_cRef);
}

STDMETHODIMP_(ULONG) TimeBeijingClassFactory::Release(void)
{
 printf("TimeBeijingClassFactory - Release/n");
 return ::InterlockedDecrement(&m_cRef);
}

STDMETHODIMP TimeBeijingClassFactory::QueryInterface(REFIID riid,void ** ppv)
{
 printf("TimeBeijingClassFactory - QueryInterface/n");

 *ppv = NULL;
 if(riid == IID_IUnknown || riid == IID_IClassFactory || riid == IID_IDispatch)//变化在此!!!
 {
  *ppv = static_cast<IClassFactory *>(this);
  reinterpret_cast<IUnknown*>(*ppv)->AddRef();
  return S_OK;
 }
 else
  return (*ppv=0),E_NOINTERFACE;
}

STDMETHODIMP TimeBeijingClassFactory::CreateInstance(IUnknown * pUnkOuter,REFIID riid,void ** ppv)
{
 printf("TimeBeijingClassFactory - CreateInstance/n");

 *ppv=NULL;
 
 if(pUnkOuter != NULL)
  return CLASS_E_NOAGGREGATION;
 
 TimeBeijingClass * pTimeBeijingClass = new TimeBeijingClass;
 if(pTimeBeijingClass == NULL)
  return E_OUTOFMEMORY;
 
 HRESULT hr = pTimeBeijingClass->QueryInterface(riid,ppv);
 
 if(FAILED(hr))
  delete pTimeBeijingClass;
 
 return hr;
 
}

STDMETHODIMP TimeBeijingClassFactory::LockServer(BOOL fLock)
{
 printf("TimeBeijingClassFactory - LockServer/n");
 if(fLock)
  ::InterlockedIncrement(&g_cObjectAndLocks);
 else
  ::InterlockedDecrement(&g_cObjectAndLocks);
 return NOERROR;
 
}

(五)服务器主文件Server.cpp(没有变化)
#include <objbase.h>
#include <initguid.h>
#include "TimeBeijing.h"
#include "TimeBeijing_i.c"
#include "TimeBeijingClassFactory.h"

HINSTANCE  g_hinstDll;//DLL实例句柄

LONG g_cObjectAndLocks;

const char * g_RegTable[][3]={//COM对象注册
 {"CLSID//{ECE8BF15-11FB-45a4-90A1-1788DDAB31AC}",
  0,
  "TimeBeijing"},

 {"CLSID//{ECE8BF15-11FB-45a4-90A1-1788DDAB31AC}//InprocServer32",
 0,
 (const char * )-1},
 
 {"CLSID//{ECE8BF15-11FB-45a4-90A1-1788DDAB31AC}//ProgID",0,"Justin.TimeBeijing.3"},
 {"Justin.TimeBeijing.3",0,"TimeBeijing"},
 {"Justin.TimeBeijing.3//CLSID",0,"{ECE8BF15-11FB-45a4-90A1-1788DDAB31AC}"},
};

//DLL入口
BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
 g_hinstDll = (HINSTANCE) hModule;//保存句柄

    return TRUE;
}


STDAPI DllUnregisterServer(void)//从注册表中注销
{
 HRESULT hr = S_OK;
 char szFileName [MAX_PATH];
 ::GetModuleFileName(g_hinstDll,szFileName,MAX_PATH);

 int nEntries = sizeof(g_RegTable) / sizeof(*g_RegTable);

 for(int i = 0; SUCCEEDED(hr) && i < nEntries; i ++)
 {
  const char * pszKeyName = g_RegTable[i][0];
  long err = ::RegDeleteKey(HKEY_CLASSES_ROOT, pszKeyName);
  if( err != ERROR_SUCCESS)
   hr = S_FALSE;
 }

 return hr;
}


STDAPI DllRegisterServer(void)//注册服务器
{
 HRESULT hr = S_OK;
 char szFileName [MAX_PATH];
 ::GetModuleFileName(g_hinstDll, szFileName, MAX_PATH);

 int nEntries = sizeof(g_RegTable) / sizeof(*g_RegTable);
 for(int i = 0 ; SUCCEEDED(hr) && i < nEntries; i ++)
 {
  const char * pszKeyName = g_RegTable[i][0];
  const char * pszValueName = g_RegTable[i][1];
  const char * pszValue = g_RegTable[i][2];

  if(pszValue == (const char *) - 1)
  {
   pszValue = szFileName;
  }

  HKEY hkey;
  long err = ::RegCreateKey(HKEY_CLASSES_ROOT, pszKeyName, &hkey);
  if(err == ERROR_SUCCESS)
  {
   err = ::RegSetValueEx( hkey,
     pszValueName,
     0,
     REG_SZ,
     ( const BYTE*)pszValue,
     ( strlen(pszValue)+1 ) );
   ::RegCloseKey(hkey);
  }
  if( err != ERROR_SUCCESS)
  {
   ::DllUnregisterServer();
   hr = E_FAIL;
  }

 }
   return hr;
}
      
STDAPI DllGetClassObject(REFCLSID rclsid ,REFIID riid,void **ppv)
{
 if(rclsid == CLSID_TimeBeijingClass)
 {
  TimeBeijingClassFactory *pFactory = new TimeBeijingClassFactory;
  
  if(pFactory == NULL)
   return E_OUTOFMEMORY;
  
  HRESULT hr = pFactory->QueryInterface(riid, ppv);
  return hr;
 }
 
 return CLASS_E_CLASSNOTAVAILABLE;
}

STDAPI DllCanUnloadNow(void)
{
 return ( g_cObjectAndLocks == 0 )
  ? S_OK : E_FAIL;
}

(六)DEF文件(没有变化)
LIBRARY "TimeBeijing.DLL"
EXPORTS
 DllCanUnloadNow     @1 PRIVATE
 DllGetClassObject   @2 PRIVATE
 DllRegisterServer   @3 PRIVATE
 DllUnregisterServer @4 PRIVATE

编译链接上述文件,得到了服务器端程序。
让我们启动服务器:regsvr32 TimeBeijing.DLL (回车)

(七)vc客户端
下面进入测试阶段,首先,我们建立vc客户端进行测试。

// TEST.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "TEST.h"
#include "../TimeBeijing_i.c"
#include "atlbase.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// The one and only application object

CWinApp theApp;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
 cout << "Initialize COM Runtime......";
 HRESULT hr = ::CoInitialize(NULL); 
 if(SUCCEEDED(hr))
  cout << "ok" << endl;
 else
 {
  cout << "failed" << endl;
  CoUninitialize();
  system("pause");
  exit(1);
 }
 
 IDispatch *pDispatch = NULL;//IDispatch 接口指针
   
 cout << "Get IDispatch Interface Pointer......";
 hr = ::CoCreateInstance(CLSID_TimeBeijingClass,
  NULL,
  CLSCTX_INPROC,
  IID_IDispatch,
  (void**)&pDispatch);

 if(SUCCEEDED(hr))
  cout << "ok" << endl;
 else
 {
  cout << "failed" << endl;
  CoUninitialize();
  system("pause");
  exit(1);
 }
 
 cout << "Now use IDispatch Interface..." << endl;

 CComVariant  varResult1;
 CComVariant  varResult2;
 CComVariant  varResult3;
 varResult1.Clear();
 varResult2.Clear();
 varResult3.Clear();

 cout << "Use Method ID.1......";
 hr = pDispatch->Invoke(0x1, // ID 1
  IID_ITimeBeijing,
  LOCALE_USER_DEFAULT,
  DISPATCH_METHOD,
  NULL,
  &varResult1,
  NULL,
  NULL);

 if(SUCCEEDED(hr))
  cout << "ok" << endl;
 else
 {
  cout << "failed" << endl;
  pDispatch->Release();
  CoUninitialize();
  system("pause");
  exit(1);
 }
  
 cout << "Use Method ID.2......";
 hr = pDispatch->Invoke(0x2, // ID 2
  IID_ITimeBeijing,
  LOCALE_USER_DEFAULT,
  DISPATCH_METHOD,
  NULL,
  &varResult2,
  NULL,
  NULL);
 
 if(SUCCEEDED(hr))
  cout << "ok" << endl;
 else
 {
  cout << "failed" << endl;
  pDispatch->Release();
  CoUninitialize();
  system("pause");
  exit(1);
 }

 cout << "Use Method ID.3......";
 hr = pDispatch->Invoke(0x3, // ID 1
  IID_ITimeBeijing,
  LOCALE_USER_DEFAULT,
  DISPATCH_METHOD,
  NULL,
  &varResult3,
  NULL,
  NULL);
 
 if(SUCCEEDED(hr))
  cout << "ok" << endl;
 else
 {
  cout << "failed" << endl;
  pDispatch->Release();
  CoUninitialize();
  system("pause");
  exit(1);
 }

 printf("Time NOW : %d - %d - %d /n", varResult1.intVal,
  varResult2.intVal, varResult3.intVal);

 cout << "Close COM Runtime......" <<endl;
 pDispatch->Release();
 ::CoUninitialize();

 system("pause");
 return 0;
}

测试结果:
Initialize COM Runtime......ok
Get IDispatch Interface Pointer......TimeBeijingClassFactory - constructor
TimeBeijingClassFactory - QueryInterface
TimeBeijingClassFactory - AddRef
TimeBeijingClassFactory - CreateInstance
TimeBeijingClass - Constructor
TimeBeijingClass - QueryInterface
TimeBeijingClass - AddRef
TimeBeijingClass - AddRef
TimeBeijingClass - Release
TimeBeijingClassFactory - Release
TimeBeijingClass - QueryInterface
TimeBeijingClass - AddRef
TimeBeijingClass - Release
ok
Now use IDispatch Interface...
Use Method ID.1......TimeBeijingClass - GetHour
ok
Use Method ID.2......TimeBeijingClass - GetMinute
ok
Use Method ID.3......TimeBeijingClass - GetMinute
ok
Time NOW : 14 - 37 - 50
Close COM Runtime......
TimeBeijingClass - Release
TimeBeijingClass - Destructor

请按任意键继续 . . .

(八)vb客户端
建立带有一个按钮的Standard EXE工程。
注意选中Project --> References -->TimeBeijingLib
输入下列代码:

Private Sub Command1_Click()
    Dim c As TimeBeijingClass
    Dim h As Integer
    Dim m As Integer
    Dim s As Integer
   
    Set c = New TimeBeijingClass
   
    h = c.GetHour
    m = c.GetMinute
    s = c.GetSecond
   
    Print "Time NOW: "; h; " - "; m; " - "; s
End Sub

显示结果如下:
Time NOW: 20 - 6 - 34

转载:点击打开链接

这篇关于如何使我们的COM对象可以被脚本语言调用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/754275

相关文章

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python

java中VO PO DTO POJO BO DO对象的应用场景及使用方式

《java中VOPODTOPOJOBODO对象的应用场景及使用方式》文章介绍了Java开发中常用的几种对象类型及其应用场景,包括VO、PO、DTO、POJO、BO和DO等,并通过示例说明了它... 目录Java中VO PO DTO POJO BO DO对象的应用VO (View Object) - 视图对象

java如何调用kettle设置变量和参数

《java如何调用kettle设置变量和参数》文章简要介绍了如何在Java中调用Kettle,并重点讨论了变量和参数的区别,以及在Java代码中如何正确设置和使用这些变量,避免覆盖Kettle中已设置... 目录Java调用kettle设置变量和参数java代码中变量会覆盖kettle里面设置的变量总结ja

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

Java将时间戳转换为Date对象的方法小结

《Java将时间戳转换为Date对象的方法小结》在Java编程中,处理日期和时间是一个常见需求,特别是在处理网络通信或者数据库操作时,本文主要为大家整理了Java中将时间戳转换为Date对象的方法... 目录1. 理解时间戳2. Date 类的构造函数3. 转换示例4. 处理可能的异常5. 考虑时区问题6.

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

Java第二阶段---09类和对象---第三节 构造方法

第三节 构造方法 1.概念 构造方法是一种特殊的方法,主要用于创建对象以及完成对象的属性初始化操作。构造方法不能被对象调用。 2.语法 //[]中内容可有可无 访问修饰符 类名([参数列表]){ } 3.示例 public class Car {     //车特征(属性)     public String name;//车名   可以直接拿来用 说明它有初始值     pu

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法   消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法 [转载]原地址:http://blog.csdn.net/x605940745/article/details/17911115 消除SDK更新时的“

【LabVIEW学习篇 - 21】:DLL与API的调用

文章目录 DLL与API调用DLLAPIDLL的调用 DLL与API调用 LabVIEW虽然已经足够强大,但不同的语言在不同领域都有着自己的优势,为了强强联合,LabVIEW提供了强大的外部程序接口能力,包括DLL、CIN(C语言接口)、ActiveX、.NET、MATLAB等等。通过DLL可以使用户很方便地调用C、C++、C#、VB等编程语言写的程序以及windows自带的大

HTML5自定义属性对象Dataset

原文转自HTML5自定义属性对象Dataset简介 一、html5 自定义属性介绍 之前翻译的“你必须知道的28个HTML5特征、窍门和技术”一文中对于HTML5中自定义合法属性data-已经做过些介绍,就是在HTML5中我们可以使用data-前缀设置我们需要的自定义属性,来进行一些数据的存放,例如我们要在一个文字按钮上存放相对应的id: <a href="javascript:" d