从 VBScript 读取 DLL(或 VB6)文件

问题描述:

我正在尝试使用 VBScript 访问 VBA 文件(或 DLL)中的函数.我有点超出我的深度,我通常不使用这两种语言中的任何一种,所以我会解释这种情况,以防有更好的解决方案.

I'm trying to use VBScript to access functions within a VBA file (or a DLL). I'm quite a bit out of my depth, and I don't normally use either of these languages, so I'll explain the situation, in case there's a better solution.

我有一个仪器,它有一个类似 VBScript 的内部窗口(它具有 VBScript 中没有的一些功能,例如Include...End Include"语句),可用于自动化仪器操作,并且我正在尝试将其与相机结合使用.对于相机,该公司提供了 VB (atmcd32d.bas) 和 C++ (atmcd32d.cpp) 文件,其中包含与 DLL 文件 (atmcd32d.dll) 通信所需的所有功能(例如 GetTemperature、StartAcquisition 等),我假设向相机发送命令.如果我使用 C++ 或 VBA,我假设我可以直接包含这些文件,这将使我的代码可以访问控制相机所需的命令.但是,主仪器的软件使用的脚本语言最接近VBScript.如果我将其更改为 .txt,该脚本允许我包含该文件,但是当它获取诸如Attribute"、ENUM"和Declare Function"之类的命令时,它当然会失败,这些命令不是 VBScript 的一部分.

I have an instrument that has an internal VBScript-like window (it has some features not found in VBScript, such as an "Include...End Include" statement) that can be used to automate instrument operation, and I'm trying to use this in combination with a camera. For the camera, the company supplied VB (atmcd32d.bas) and C++ (atmcd32d.cpp) files containing all the necessary functions (e.g., GetTemperature, StartAcquisition, etc.) for communicating with a DLL file (atmcd32d.dll), which I assume sends commands to the camera. If I were using C++ or VBA, I assume I could directly include those files, which would give my code access to the commands needed to control the camera. However, the scripting language used by the software of the main instrument is closest to VBScript. The script lets me include the file if I change it to .txt, but of course it fails when it gets to commands like "Attribute", "ENUM", and "Declare Function", which aren't part of VBScript.

首先,我想知道是否有更好的方法来运行 .bas 文件.

I was wondering, first, if there's a better way to run the .bas file.

或者,我想我可以尝试从 .bas 文件中翻译我需要的函数,这样我就可以从 VBScript 与 DLL 进行通信.这将一个问题变成了两个问题.它造成的第一个问题是翻译,我不确定这是否是一种现实的方法.既然是750行的文件,想先问问别人.

Alternatively, I thought I could try to translate the functions that I need from the .bas file, so I could communicate with the DLL from VBScript. This changes one problem into 2 problems. The first problem it creates is the translation, and I'm not sure if that's a realistic approach. Since it's a 750 line file, I wanted to ask others first.

第二个问题是如何与DLL通信.我找到了一个关于使用 VBScript 与 DLL 通信的页面:How从 VBScript 调用 C# DLL 函数

The second problem is how to communicate with the DLL. I found a page on using VBScript to communicate with a DLL: How to call C# DLL function from VBScript

我尝试使用这种方法.就我而言,我假设 DLL 已经注册,因为它是与相机软件一起安装的,所以我只需要使用:

And I tried to use that approach. For my case, I assumed that the DLL is already registered, since it was installed along with the camera software, so I just need to use:

Set obj = CreateObject("C:\MyPath\atmcd32d.dll")

访问相机功能.但是,如果我仅使用该行运行脚本,则会收到消息ActiveX 组件无法创建对象".这是否意味着未注册 DLL?还是我犯了其他错误?

to get access to the camera functions. But if I run a script with only that line, I get the message "ActiveX component can't create object". Does this mean the DLL isn't registered? Or did I make some other error?

对于这个令人费解的问题,我深表歉意,但考虑到我已经不知所措,我想我应该先寻求帮助,然后再向错误的方向深入挖掘.

I apologize for the convoluted question, but given how far I've gotten in over my head already, I figured I should ask for help before I dug too deeply in the wrong direction.

我从您的 Andor 相机文档中得到的印象(https://neurophysics.ucsd.edu/Manuals/Andor%20Technology/Andor_Software_Development_Kit.pdf) 是 DLL 将不能从 VBScript 直接访问.

The impression I get from what seems to be the documentation for your Andor camera (https://neurophysics.ucsd.edu/Manuals/Andor%20Technology/Andor_Software_Development_Kit.pdf) is that the DLL is not going to be directly accessible from VBScript.

文档是这样说的:

在构建您自己的项目时,您必须包含文件 ATMCD32D.BAS.此文件包含用于接口的 Andor SDK 函数原型使用动态链接库 ATMCD32D.DLL

When building you own projects you must include the file ATMCD32D.BAS. This file contains the Andor SDK function prototypes for interfacing with the dynamic link library ATMCD32D.DLL

他们在这里指的不是 VBScript,而是 BASIC 的更标准"版本,例如 VB.NET 或现在相当老的 VB6(经典"VB).这些语言具有直接调用 DLL 中的函数的功能,例如它们的.

They are not referring to VBScript here, but probably a more 'standard' version of BASIC such as VB.NET or the now quite old VB6 ("classic" VB). Those languages have features to directly call functions in a DLL such as theirs.

另一方面,VBSCript 显然只能访问支持 COM 规范的外部 DLL.考虑 COM 的一种方式是,它是一种使对象(或类)可从 DLL 访问的标准方式——但不仅仅是像 C 语言那样的普通函数.但是他们的 DLL 似乎不会直接支持 COM.(但要仔细检查这一点,请参阅 https://*.com/a/3011424/3195477https://*.com/a/49920874/3195477).

VBSCript on the other hand apparently only has the ability to access external DLLs which support the COM specifications. One way to think of COM is that it is a standard way of making objects (or classes) accessible from a DLL - but not just plain functions like you would get from a language like C for instance. However their DLL doesn't seem like it would directly support COM. (But to double check this, see https://*.com/a/3011424/3195477 or https://*.com/a/49920874/3195477).

因此,您需要做的是编写自己的代码,作为 Andor DLL 中函数的包装器.该包装 DLL 需要提供 COM 类,这些 COM 类依次调用实际的 Andor DLL 函数.这个包装器可以用任何能够生成 COM 可见 DLL 的语言编写.建议您为此使用 VB.NET,因为这可能是合并 ATMCD32D.BAS 文件的最简单途径.该文件的语法很可能与 VB.NET 完全兼容(但是我自己无法验证).

So what you will need to do is write your own code that will act as a wrapper around the functions in the Andor DLL. That wrapper DLL needs to provide COM classes which in turn call the actual Andor DLL functions. This wrapper could be written in any language that is capable of producing a COM-visible DLL. A suggestion is that you use VB.NET for this, because that might be the simplest route to incorporate the ATMCD32D.BAS file. The syntax of that file is likely to be fully compatible with VB.NET (can't verify that myself, however).

Visual Studio 不仅能够为您生成这样的 DLL,而且还能够使用 .NET 工具或多或少地自动生成您需要的 COM 层.在 VB.NET 项目中,您需要创建(至少)一个将从 VBScript 调用的类.该类应该具有与您需要使用的 Andor DLL 中的任何函数相对应的函数.您不必将它们全部包括在内 - 事实上,作为第一步,我只会做您能想到的最基本的事情,作为确认所有接线"的概念证明.是正确的.类函数可以从字面上匹配名称 &DLL 函数的参数,或者您可以根据需要添加一些额外的逻辑.

Visual Studio is more than capable of producing such a DLL for you, and will also be able to use .NET tools to more or less automatically generate the COM layer that you will need. In a VB.NET project you need to create (at least) one class which you will call from VBScript. That class should have functions corresponding to whatever functions in the Andor DLL you need to use. You don't have to include them all - in fact as a first step I would just do the most basic thing you can think of as a proof of concept to confirm all the "wiring" is correct. The class functions could literally just match the names & parameters of the DLL functions, or you could add some additional logic as needed.

总而言之,以下是我将遵循的步骤:

So in summary, here are the steps I would follow:

  1. 运行 Visual Studio
  2. 创建一个新的 VB.NET 类库项目
  3. 在项目属性中,确保将其设置为注册为 COM-visible(我忘记了此选项的确切措辞)
  4. 添加一个类,比如说WrapperClass
  5. 也许您可以将 .BAS 文件的内容复制到此类中.它应该包含一堆 DECLARE FUNCTION 语句,我期望.
  6. 将公共 SUBFUNCTION 添加到您的类中,它们只调用 DECLARE ed 函数.
  7. 确保该类应用了 属性,我也会使用 为此.
  8. 在 Visual Studio 中编译类库项目.如果一切设置正确,它还会注册它为您创建的 DLL.
  9. 可能您需要将 Andor DLL 复制到与包装 DLL 相同的位置(通常为project\bin\debug\ 文件夹)
  10. 在 VBScript 中,您可以执行以下操作:
  1. Run Visual Studio
  2. Create a new VB.NET class library project
  3. In the project properties, make sure it is set to register as COM-visible (I forget the exact wording of this option)
  4. Add a class, let's say WrapperClass
  5. Probably you can copy the contents of the .BAS file into this class. It should contain a bunch of DECLARE FUNCTION statements, I expect.
  6. Add public SUBs or FUNCTIONs to your class which just call the DECLAREed functions.
  7. Make sure the class has the <COMVisible(true)> attribute applied to it, and I would also use <ClassInterface(ClassInterfaceType.AutoDual)> for this.
  8. Compile the class library project in Visual Studio. If everything is setup correctly it will also register the DLL it creates for you.
  9. Probably you will need to copy the Andor DLL to the same location as your wrapper DLL (project\bin\debug\ folder typically)
  10. In VBScript you can then do things like:

Set obj = CreateObject("WrapperClass")   
Call obj.WrapperFunction1 ...

(我倾向于使用 C# 而不是 VB.NET,但我认为上面的策略是正确的,这些细节基本相同.)

(I tend to use C# instead of VB.NET but I think the strategy above is correct, these details would be mostly the same.)

准备好解决实施中的任何问题可能需要一些时间.与 COM 相关的事情并不太复杂,但有很多小陷阱.此外,这还假设了您正在使用的 VBScript 环境的专有性质.

Be prepared that it may take some time to work out any kinks in your implementation. What you have to do with COM is not too complex but there are plenty of small pitfalls. Also this assumes a lot about the proprietary nature of the VBScript environment that you are using.

如果您没有在将运行 VBScript 程序的同一台 PC 上运行 Visual Studio,那么您将需要执行一些额外的步骤来手动复制 &然后在该 PC 上注册包装 DLL(以便 CreateObject 可以工作).在这种情况下也可以想象可能需要 .NET 更新.如果您能找出那台 PC 上已经存在的 .NET 版本,我将设置包装器 DLL 以针对所述版本进行编译;对于您需要编写的代码,它实际上可能并不重要.

If you are not running Visual Studio on the same PC which will be running the VBScript program then you will need to do some extra steps to manually copy & then register the wrapper DLL on that PC (so that CreateObject will work). It is also conceivable in this circumstance that a .NET update may be needed. If you can find out what version of .NET is already on that PC I would just set the wrapper DLL to compile against said version; it probably won't actually matter for the code you need to write.