3

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.

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.

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

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.

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

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")

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.

Matt
  • 31
  • 2
  • 4
    CreateObject is used to create an instance of a class defined in your registered dll. Because it is registered you don't need to provide the path to the dll. The fully qualified name of the class is enough. (that is also what the answer to the linked question says) – Geert Bellekens Apr 23 '21 at 03:46
  • 1
    There is a bunch of useful information in [this answer](https://stackoverflow.com/a/35985827/692942) which covers COM DLL registration and how to check it’s registered in the correct windows subsystem. There’s also a checklist to read through, which will help you diagnose the problem. – user692942 Apr 23 '21 at 07:16
  • 1
    Does this answer your question? [Using DLLs in VBScript](https://stackoverflow.com/questions/9839704/using-dlls-in-vbscript) – user692942 Apr 23 '21 at 08:56
  • 3
    If atmcd32d.bas contains "Declare Function..." lines like Declare Function Initialize Lib "atmcd32d.dll" (ByVal dirName As String) As Long then atmcd32d.dll is not an ActiveX/COM dll so CreateObject function can't be used for interfacing with the ATMCD32D.DLL. Check out user's guide for Andor SDK from https://neurophysics.ucsd.edu/Manuals/Andor%20Technology/Andor_Software_Development_Kit.pdf – Smith Apr 23 '21 at 09:38
  • @Smith You found my brand of camera. Yes, atmcd32d.bas contains Declare Function lines that look like that, so it sounds like this is one of the problems. I will search through the manual again. There must be some way to communicate with it, because the Nova software for the other instrument already accesses some camera functions. It just doesn't allow me to coordinate them. – Matt Apr 23 '21 at 13:02
  • 1
    @user692942 Thank you. The second link clarifies Geert's point--that I put the wrong information in the CreateObject statement. The first link will take me a little longer, but it will be good to learn how this statement works, so I can give it the right information. – Matt Apr 23 '21 at 13:09
  • 2
    An ActiveX/COM wrapper for ATMCD32D.DLL (just for the necessary functions) could do the trick regarding the usage of CreateObject function. – Smith Apr 23 '21 at 13:34
  • 1
    What is the vendor or name of the special variant of VBScript that you are using? A lot will come down to what features that language has. – StayOnTarget Apr 26 '21 at 14:23
  • @StayOnTarget I'm not sure. The VBScript I'm using is accessed using a window built into another program called Nova, from NT-MDT. This program is mainly used to operate an atomic force microscope, and they added the VBScript window to give users more control. I don't have any idea how they implemented this. I am a little worried I'll finally get this all figured out only to find that Nova doesn't let me do it. – Matt Apr 28 '21 at 02:14

1 Answers1

2

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.

The docs say this:

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

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 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://stackoverflow.com/a/3011424/3195477 or https://stackoverflow.com/a/49920874/3195477).

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 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. 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 ...

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

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.

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.

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
  • I’m building up to this in small steps. To practice, I created a DLL in vb.net to add 2 numbers and registered it using `Register for COM interop` and `Make assembly COM-visible`. I couldn’t find `ClassInterfaceType`, so I skipped it. I can make a VB.Net Console function that sends two numbers to the `addition` DLL and prints the result, but it only works if I reference the DLL using the `Add Reference` menu item in Visual Studio. Since `Add Reference` isn’t an option in the VBScript window, I tried to `CreateObject` without it, but I get “ActiveX component can’t create object”. – Matt May 04 '21 at 09:11
  • You may just be missing `Imports System.Runtime.InteropServices` in your VB source file? That should enable `ClassInterfaceType` to be found. Your approach is sound, testing that `CreateObject` can instantiate your class is exactly what you want to do. When that works you'll know all the "plumbing" is right. – StayOnTarget May 04 '21 at 11:30