Содержание
- CALL function
- Description
- Syntax
- Example
- API calls from Excel
- How to make API calls from Excel and transform JSON response to a table.
- API Call from Visual Basic script
- API Call from “New Query”, in “Data” tab
- Using the CALL and REGISTER functions
- In this article
- Description
- Data Types
- Remarks
- Additional Data Types Information
- F and G Data Types
- K Data Type
- O Data Type
- P Data Type
- R Data Type — Calling Microsoft Excel Functions from DLLs
- Volatile Functions and Recalculation
- Modifying in Place — Functions Declared as Void
- How to call .NET methods from Excel VBA?
- 1. XLLs
- 2. Automation AddIns
- 3. Calling .Net from Excel VBA
CALL function
Important: Caution Incorrectly editing the registry may severely damage your operating system, requiring you to reinstall it. Microsoft cannot guarantee that problems resulting from editing the registry incorrectly can be resolved. Before editing the registry, back up any valuable data. For the most recent information about using and protecting your computer’s registry, see Microsoft Windows Help.
This article describes the formula syntax and usage of the CALL function in Microsoft Excel.
Note: The CALL function is not available in Excel for the web.
Description
Calls a procedure in a dynamic link library or code resource. There are two syntax forms of this function. Use syntax 1 only with a previously registered code resource, which uses arguments from the REGISTER function. Use syntax 2a or 2b to simultaneously register and call a code resource.
Important: This function is provided for advanced users only. If you use the CALL function incorrectly, you may cause errors that will require you to restart your computer. This function is only available from an Excel macro sheet.
Syntax
Used with REGISTER
Used alone (in Microsoft Excel for Windows)
Register_id is the value returned by a previously executed REGISTER or REGISTER.ID function.
The CALL function syntax has the following arguments:
Module_text Required. Quoted text specifying the name of the dynamic link library (DLL) that contains the procedure in Microsoft Excel for Windows.
Procedure Required. Text specifying the name of the function in the DLL in Microsoft Excel for Windows. You can also use the ordinal value of the function from the EXPORTS statement in the module-definition file (.DEF). The ordinal value must not be in the form of text.
Type_text Required. Text specifying the data type of the return value and the data types of all arguments to the DLL or code resource. The first letter of type_text specifies the return value. The codes you use for type_text are described in detail in Using the CALL and REGISTER functions. For stand-alone DLLs or code resources (XLLs), you can omit this argument.
Argument1. Optional. The arguments to be passed to the procedure.
Example
The following macro formula registers the GetTickCount function from 32-bit Microsoft Windows. GetTickCount returns the number of milliseconds that have elapsed since Microsoft Windows was started.
Assuming that this REGISTER function is in cell A5, after your macro registers GetTickCount, you can use the CALL function to return the number of milliseconds that have elapsed:
Источник
API calls from Excel
How to make API calls from Excel and transform JSON response to a table.
Nobody can deny that Microsoft Excel is still a powerful tool even if you know Python, SQL, Javascript… It provides a super-friendly interface, has many functionalities and is a very popular software.
On the other hand, being able to make API calls and process the response provides a new world of endless possibilities. Nowadays many companies give access to their data via certain endpoints.
Why not put these 2 tools together? In this article we’ll explain how to do it.
There are 2 main ways in Excel to do it:
- Via Visual Basic script
- Via making a “query” from the data menu
API Call from Visual Basic script
The first thing is enable the “developer” menu. This can be done in File → Options → Customize Ribbon:
Once this is done we have to open the VBA editor.
In order to process the JSON response of the API call, we need to add the JsonConverter module, which can be found in the following url: https://github.com/VBA-tools/VBA-JSON/releases, then import JsonConverter.bas into the project. In the VBA Editor, go to File → Import.
Then we also need to import 2 references into the project from the “Tools” menu.
- Microsoft XML, v6.0
- Microsoft Scripting Runtime
Next we have to create a new module to write the code that will make the api call. Here I present 2 examples:
- Get the people from the Star Wars API (https://swapi.dev/).
If you want to save the excel file, remember to use the “xlsm” extension, which allows macros.
API Call from “New Query”, in “Data” tab
Excel 2016 has a built-in feature that allows to make API calls. Previous versions can also make it, but installing the PowerQuery plugin. To make an API call we must go to the “Data” tab and click on “New Query” → “From Other Sources” → “From Web”.
Then we click on “Advanced”. Here we put the url, and if credentials are needed, they can be entered as a header.
Источник
Using the CALL and REGISTER functions
Important: Caution Incorrectly editing the registry may severely damage your operating system, requiring you to reinstall it. Microsoft cannot guarantee that problems resulting from editing the registry incorrectly can be resolved. Before editing the registry, back up any valuable data. For the most recent information about using and protecting your computer’s registry, see Microsoft Windows Help.
This article describes the formula syntax and usage of the CALL, REGISTER, and REGISTER.ID functions in Microsoft Excel.
Note: The CALL and REGISTER functions are not available in Excel for the web.
In this article
Description
The following describes the argument and return value data types used by the CALL, REGISTER, and REGISTER.ID functions. Arguments and return values differ slightly depending on your operating environment, and these differences are noted in the data type table.
Data Types
In the CALL, REGISTER, and REGISTER.ID functions, the type_text argument specifies the data type of the return value and the data types of all arguments to the DLL function or code resource. The first character of type_text specifies the data type of the return value. The remaining characters indicate the data types of all the arguments. For example, a DLL function that returns a floating-point number and takes an integer and a floating-point number as arguments would require «BIB» for the type_text argument.
The following table contains a complete list of the data type codes that Microsoft Excel recognizes, a description of each data type, how the argument or return value is passed, and a typical declaration for the data type in the C programming language.
Logical
(FALSE = 0), TRUE = 1)
IEEE 8-byte floating-point number
Null-terminated string (maximum string length = 255)
Byte-counted string (first byte contains length of string, maximum string length = 255 characters)
IEEE 8-byte floating-point number
Null-terminated string (maximum string length = 255 characters)
Reference (modify in place)
Byte-counted string (first byte contains length of string, maximum string length = 255 characters)
Reference (modify in place)
Unsigned 2-byte integer
unsigned short int
Signed 2-byte integer
Signed 4-byte integer
Logical
(FALSE = 0, TRUE = 1)
Signed 2-byte integer
Signed 4-byte integer
Three arguments are passed:
unsigned short int *
unsigned short int *
double [ ]
Microsoft Excel OPER data structure
Microsoft Excel XLOPER data structure
The C-language declarations are based on the assumption that your compiler defaults to 8-byte doubles, 2-byte short integers, and 4-byte long integers.
In the Microsoft Windows programming environment, all pointers are far pointers. For example, you must declare the D data type code as unsigned char far * in Microsoft Windows.
All functions in DLLs and code resources are called using the Pascal calling convention. Most C compilers allow you to use the Pascal calling convention by adding the Pascal keyword to the function declaration, as shown in the following example: pascal void main (rows,columns,a)
If a function uses a pass-by-reference data type for its return value, you can pass a null pointer as the return value. Microsoft Excel will interpret the null pointer as the #NUM! error value.
Additional Data Types Information
This section contains detailed information about the F, G, K, O, P, and R data types and other information about the type_text argument.
F and G Data Types
With the F and G data types, a function can modify a string buffer that is allocated by Microsoft Excel. If the return value type code is F or G, then Microsoft Excel ignores the value returned by the function. Instead, Microsoft Excel searches the list of function arguments for the first corresponding data type (F or G) and then takes the current contents of the allocated string buffer as the return value. Microsoft Excel allocates 256 bytes for the argument, so the function may return a larger string than it received.
K Data Type
The K data type uses a pointer to a variable-size FP structure. You must define this structure in the DLL or code resource as follows:
The declaration double array[1] allocates storage for only a single-element array. The number of elements in the actual array equals the number of rows multiplied by the number of columns.
O Data Type
The O data type can be used only as an argument, not as a return value. It passes three items: a pointer to the number of rows in an array, a pointer to the number of columns in an array, and a pointer to a two-dimensional array of floating-point numbers.
Instead of returning a value, a function can modify an array passed by the O data type. To do this, you can use «>O» as the type_text argument. For more information, see «Modifying in Place — Functions Declared as Void» below.
The O data type was created for direct compatibility with Fortran DLLs, which pass arguments by reference.
P Data Type
The P data type is a pointer to an OPER structure. The OPER structure contains 8 bytes of data, followed by a 2-byte identifier that specifies the type of data. With the P data type, a DLL function or code resource can take and return any Microsoft Excel data type.
The OPER structure is defined as follows:
typedef struct _oper
The type field contains one of these values.
Val field to use
String (first byte contains length of string)
Error: the error values are:
The last two values can be used only as arguments, not return values. The missing argument value (128) is passed when the caller omits an argument. The empty cell value (256) is passed when the caller passes a reference to an empty cell.
R Data Type — Calling Microsoft Excel Functions from DLLs
The R data type is a pointer to an XLOPER structure, which is an enhanced version of the OPER structure. In Microsoft Excel version 4.0 and later, you can use the R data type to write DLLs and code resources that call Microsoft Excel functions. With the XLOPER structure, a DLL function can pass sheet references and implement flow control, in addition to passing data. A complete description of the R data type and the Microsoft Excel application programming interface (API) is beyond the scope of this topic. The Microsoft Office XP Developer’s Guide contains detailed information about the R data type, the Microsoft Excel API, and many other technical aspects of Microsoft Excel.
Volatile Functions and Recalculation
Microsoft Excel usually calculates a DLL function (or a code resource) only when it is entered into a cell, when one of its precedents changes, or when the cell is calculated during a macro. On a worksheet, you can make a DLL function or code resource volatile, which means that it recalculates every time the worksheet recalculates. To make a function volatile, add an exclamation point (!) as the last character in the type_text argument.
For example, in Microsoft Excel for Windows, the following worksheet formula recalculates every time the worksheet recalculates:
Modifying in Place — Functions Declared as Void
You can use a single digit n for the return type code in type_text, where n is a number from 1 to 9. This tells Microsoft Excel to modify the variable in the location pointed to by the nth argument in type_text, instead of returning a value. This is also known as modifying in place. The nth argument must be a pass-by-reference data type (C, D, E, F, G, K, L, M, N, O, P, or R). The DLL function or code resource must also be declared with the void keyword in the C language (or the procedure keyword in the Pascal language).
For example, a DLL function that takes a null-terminated string and two pointers to integers as arguments can modify the string in place. Use «1FMM» as the type_text argument, and declare the function as void.
Versions prior to Microsoft Excel 4.0 used the > character to modify the first argument in place; there was no way to modify any argument other than the first. The > character is equivalent to n = 1 in Microsoft Excel version 4.0 and later.
Источник
How to call .NET methods from Excel VBA?
The default policy is preventing the CLR 4 from excuting the legacy code from the CLR 2 :
To enable the legacy execution, you can either create the file excel.exe.config in the folder where excel.exe is located:
Or you can call the native function CorBindToRuntimeEx instead of New mscoree.CorRuntimeHost :
I’m not sure if this was just a coincidence or because I posted related question. SO showed me your question and I think I could also contribute something.
When working with VBA and DLL, most solutions that I’ve seen so far is telling me to register the DLL and make it com/gac visible. If you are doing this in your PC that’s absolutely fine but if you are distributing your VBA application, you don’t really want to install DLLs in their system. You might not have permission or you don’t really want to go through install/uninstall process or messing with referencing issues.
However you can load dlls dynamically using some windows APIs.
DLL
Now the question is how to access .NET dll from vba? if your clients have mixed os architecture x86 x64 you need to handle this accordingly. Lets assume we are working on 32bit office/Excel.
If you create a .NET dll and would like to access it from VBA it will throw an error message similar to «Can’t find the dll entry point». thankfully Robert Giesecke has created an abstract wrapper which will allow you to create simple DLL consumable via VBA.
A template can be found here.
All you have to do
- Create a new class project in visual studio
- Set the project platform either x86 for 32bit and otherwise
- Create your methods within a main class.
- create another class which will return your main class as object (is returning to vba)
- (follow the template from his website)
Lets assume you have followed his template and created a test method as following.
and your unmanagedexport class:
Preparing to access the dll from vba side
Add the DLL to your root folder:
Now It’s all about loading the dll and creating & accessing objects it in vba. that would be:
the output should be
Advantages I personally don’t like installing and referencing dlls. By following above template, you don’t need to reference anything, you don’t need to install anything just load and work with your the DLL with full freedom.
NOTE: I assume the dll/.net code is yours and you can compile it again with above templates to.
I had success with above template and created a .NET non-blocking notifications for vba you can have a look here: non-blocking «toast» like notifications for Microsoft Access (VBA)
Here’s your solution, tested for .NET 2.0 and .NET 4.0, 32 bit and 64 bit, courtesy of Soraco Technologies.
The solution proposed below uses late binding and does not require registration of the .NET assemblies.
Declarations
Add the following declarations to your project:
Initialization
You must initialize the m_homeDir variable to the path where the .NET assemblies are located.
For example, if you install the .NET assemblies in the same folder as the Excel or MS-Access files, you should initialize m_homeDir to:
Excel: m_homeDir = ThisWorkbook.Path
Access: m_homeDir = CurrentProject.Path
.NET Object Creation
Add the following code to your project.
Instantiate the .NET object
Now you are ready to instantiate your .NET object and start using it. Add the following code to your application:
The first argument is the full path to the .NET DLL.
The second argument is the fully qualified name of the requested type, including the namespace but not the assembly, as returned by the Type.FullName property.
Required DLLs
The solution requires deployment of 2 DLLs that are responsible for hosting the .NET CLR. The DLLs are expected to be deployed in the same folder as your Excel or MS-Access file.
The DLLs can be downloaded from Soraco’s web site: https://soraco.co/products/qlm/QLMCLRHost.zip
Licensing LGPL-2.1
We hereby grant you the right to use our DLLs as long as your application does not compete directly or indirectly with Quick License Manager. You can use these DLLs in your commercial or non-commercial applications.
Here is a canonical answer on the 3 main methods to call .Net from Excel (or VBA).
All three ways work in .Net 4.0.
1. XLLs
The 3rd party vendor Add-In Express offer XLL functionality, however its free and easy to use Excel-DNA the author is here https://stackoverflow.com/users/44264
Here is an extract from the Excel-DNA page: https://excel-dna.net/
Excel-DNA is an independent project to integrate .NET into Excel. With Excel-DNA you can make native (.xll) add-ins for Excel using C#, Visual Basic.NET or F#, providing high-performance user-defined functions (UDFs), custom ribbon interfaces and more. Your entire add-in can be packed into a single .xll file requiring no installation or registration.
If you are using a version of Visual Studio that supports the NuGet Package Manager (including Visual Studio 2012 Express for Windows Desktop), the easiest way to make an Excel-DNA add-in is to:
Create a new Class Library project in Visual Basic, C# or F#. Use the Manage NuGet Packages dialog or the Package Manager Console to install the Excel-DNA package:
Add your code (C#, Visual Basic.NET or F#):
Compile, load and use your function in Excel:
2. Automation AddIns
This article by Eric Carter shows how to do it, the article is missing heaps of images so I am copy / pasting the entire article and have recreated the images for preservation.
Excel enables the creation of user defined functions that can be used in Excel formulas. A developer must create a special kind of DLL called an XLL. Excel also allows you to write custom functions in VBA that can be used in Excel formulas. Unfortunately, Excel does not support or recommend writing an XLL that uses managed code. If you are willing to take your chances that your XLL might not run in current or future versions of Excel, there are solutions available that enable this scenario—search the web for “managed XLL”.
Fortunately, there is an easier way to create a user defined function that doesn’t require you to create an XLL dll. Excel XP, Excel 2003, and Excel 2007 support something called an Automation Add-in. An Automation Add-in can be created quite simply in C# or VB.NET. I’m going to show you an example in C#.
First, launch Visual Studio and create a new C# class library project called AutomationAddin for this example.
Then, in your Class1.cs file, enter the code shown below. Replace the GUID with your own GUID that you create by using Generate GUID in the Tools menu of Visual Studio.
With this code written, show the properties for the project by double clicking on the properties node under the project in Solution Explorer. Click on the Build tab and check the check box that says “Register for COM Interop”. At this point you have an extra step if you are running on Windows Vista or higher. Visual Studio has to be run with administrator privileges to register for COM interop. Save your project and exit Visual Studio. Then find Visual Studio in the Start menu and right click on it and choose “Run as Administrator”. Reopen your project in Visual Studio. Then choose “Build” to build the add-in.
Now launch Excel and get to the Automation servers dialog by following these steps:
You can find the class you created by looking for AutomationAddin.MyFunctions in the list of Automation add-ins:
Now, let’s try to use the function MultiplyNTimes inside Excel. First create a simple spreadsheet that has a number, a second number to multiple the first by, and a third number for how many times you want to multiply the first number by the second number. An example spreadsheet is shown here:
Click on an empty cell in the workbook below the numbers and then click on the Insert Function button in the formula bar. From the dialog of available formulas, drop down the “Or select a category” drop down box and choose “AutomationAddin.MyFunctions.
Then click on the MultiplyNTimes function as shown here:
When you press the OK button, Excel pops up a dialog to help you grab function arguments from the spreadsheet as shown here:
Finally, click OK and see your final spreadsheet as shown here with your custom formula in cell C3.
3. Calling .Net from Excel VBA
REF: Calling a .net library method from vba
Using the code from the Automation.AddIn project we can easily call the MultiplyNTimes function from Excel VBA.
First Add a reference to the DLL from Excel, to do this you will need to be in the VB Editor. Press Alt + F11, then click Tools menu and References:
Select the AutomationAddIn DLL:
Add VBA code to call the .Net DLL:
Please note if you’re working with Classes in C# you will need to mark them with ClassInterface, with an Interface marked with ComVisible = true: Use CLR classes from COM addin in Excel VBA?
Finally there are some excellent MSDN articles about Excel and .Net by «Andrew Whitechapel» — google them
Источник
Important:
Caution Incorrectly editing the registry may severely damage your operating system, requiring you to reinstall it. Microsoft cannot guarantee that problems resulting from editing the registry incorrectly can be resolved. Before editing the registry, back up any valuable data. For the most recent information about using and protecting your computer’s registry, see Microsoft Windows Help.
This article describes the formula syntax and usage of the CALL, REGISTER, and REGISTER.ID functions in Microsoft Excel.
Note: The CALL and REGISTER functions are not available in Excel for the web.
In this article
-
Description
-
Data Types
-
Remarks
-
Additional Data Types Information
-
F and G Data Types
-
K Data Type
-
O Data Type
-
P Data Type
-
R Data Type — Calling Microsoft Excel Functions from DLLs
-
Volatile Functions and Recalculation
-
Modifying in Place — Functions Declared as Void
-
Description
The following describes the argument and return value data types used by the CALL, REGISTER, and REGISTER.ID functions. Arguments and return values differ slightly depending on your operating environment, and these differences are noted in the data type table.
Top of Page
Data Types
In the CALL, REGISTER, and REGISTER.ID functions, the type_text argument specifies the data type of the return value and the data types of all arguments to the DLL function or code resource. The first character of type_text specifies the data type of the return value. The remaining characters indicate the data types of all the arguments. For example, a DLL function that returns a floating-point number and takes an integer and a floating-point number as arguments would require «BIB» for the type_text argument.
The following table contains a complete list of the data type codes that Microsoft Excel recognizes, a description of each data type, how the argument or return value is passed, and a typical declaration for the data type in the C programming language.
Code |
Description |
Pass by |
C Declaration |
A |
Logical |
Value |
short int |
B |
IEEE 8-byte floating-point number |
Value Reference (Macintosh) |
double double * (Macintosh) |
C |
Null-terminated string (maximum string length = 255) |
Reference |
char * |
D |
Byte-counted string (first byte contains length of string, maximum string length = 255 characters) |
Reference |
Unsigned char * |
E |
IEEE 8-byte floating-point number |
Reference |
double * |
F |
Null-terminated string (maximum string length = 255 characters) |
Reference (modify in place) |
char * |
G |
Byte-counted string (first byte contains length of string, maximum string length = 255 characters) |
Reference (modify in place) |
unsigned char * |
H |
Unsigned 2-byte integer |
Value |
unsigned short int |
I |
Signed 2-byte integer |
Value |
short int |
J |
Signed 4-byte integer |
Value |
long int |
K |
Array |
Reference |
FP * |
L |
Logical |
Reference |
short int * |
M |
Signed 2-byte integer |
Reference |
short int * |
N |
Signed 4-byte integer |
Reference |
long int * |
O |
Array |
Reference |
Three arguments are passed: |
P |
Microsoft Excel OPER data structure |
Reference |
OPER * |
R |
Microsoft Excel XLOPER data structure |
Reference |
XLOPER * |
Top of Page
Remarks
-
The C-language declarations are based on the assumption that your compiler defaults to 8-byte doubles, 2-byte short integers, and 4-byte long integers.
-
In the Microsoft Windows programming environment, all pointers are far pointers. For example, you must declare the D data type code as unsigned char far * in Microsoft Windows.
-
All functions in DLLs and code resources are called using the Pascal calling convention. Most C compilers allow you to use the Pascal calling convention by adding the Pascal keyword to the function declaration, as shown in the following example: pascal void main (rows,columns,a)
-
If a function uses a pass-by-reference data type for its return value, you can pass a null pointer as the return value. Microsoft Excel will interpret the null pointer as the #NUM! error value.
Top of Page
Additional Data Types Information
This section contains detailed information about the F, G, K, O, P, and R data types and other information about the type_text argument.
F and G Data Types
With the F and G data types, a function can modify a string buffer that is allocated by Microsoft Excel. If the return value type code is F or G, then Microsoft Excel ignores the value returned by the function. Instead, Microsoft Excel searches the list of function arguments for the first corresponding data type (F or G) and then takes the current contents of the allocated string buffer as the return value. Microsoft Excel allocates 256 bytes for the argument, so the function may return a larger string than it received.
Top of Page
K Data Type
The K data type uses a pointer to a variable-size FP structure. You must define this structure in the DLL or code resource as follows:
typedef struct _FP
{
unsigned short int rows;
unsigned short int columns;
double array[1]; /* Actually, array[rows][columns] */
} FP;
The declaration double array[1] allocates storage for only a single-element array. The number of elements in the actual array equals the number of rows multiplied by the number of columns.
Top of Page
O Data Type
The O data type can be used only as an argument, not as a return value. It passes three items: a pointer to the number of rows in an array, a pointer to the number of columns in an array, and a pointer to a two-dimensional array of floating-point numbers.
Instead of returning a value, a function can modify an array passed by the O data type. To do this, you can use «>O» as the type_text argument. For more information, see «Modifying in Place — Functions Declared as Void» below.
The O data type was created for direct compatibility with Fortran DLLs, which pass arguments by reference.
Top of Page
P Data Type
The P data type is a pointer to an OPER structure. The OPER structure contains 8 bytes of data, followed by a 2-byte identifier that specifies the type of data. With the P data type, a DLL function or code resource can take and return any Microsoft Excel data type.
The OPER structure is defined as follows:
typedef struct _oper
{
union
{
double num;
unsigned char *str;
unsigned short int bool;
unsigned short int err;
struct
{
struct _oper *lparray;
unsigned short int rows;
unsigned short int columns;
} array;
} val;
unsigned short int type;
} OPER;
The type field contains one of these values.
Type |
Description |
Val field to use |
1 |
Numeric |
num |
2 |
String (first byte contains length of string) |
str |
4 |
Boolean (logical) |
bool |
16 |
Error: the error values are: 0#NULL! 7#DIV/0! 15#Value! 23#REF! 29#NAME? 36#NUM! 42#N/A |
err |
64 |
Array |
array |
128 |
Missing argument |
|
256 |
Empty cell |
The last two values can be used only as arguments, not return values. The missing argument value (128) is passed when the caller omits an argument. The empty cell value (256) is passed when the caller passes a reference to an empty cell.
Top of Page
R Data Type — Calling Microsoft Excel Functions from DLLs
The R data type is a pointer to an XLOPER structure, which is an enhanced version of the OPER structure. In Microsoft Excel version 4.0 and later, you can use the R data type to write DLLs and code resources that call Microsoft Excel functions. With the XLOPER structure, a DLL function can pass sheet references and implement flow control, in addition to passing data. A complete description of the R data type and the Microsoft Excel application programming interface (API) is beyond the scope of this topic. The Microsoft Office XP Developer’s Guide contains detailed information about the R data type, the Microsoft Excel API, and many other technical aspects of Microsoft Excel.
Top of Page
Volatile Functions and Recalculation
Microsoft Excel usually calculates a DLL function (or a code resource) only when it is entered into a cell, when one of its precedents changes, or when the cell is calculated during a macro. On a worksheet, you can make a DLL function or code resource volatile, which means that it recalculates every time the worksheet recalculates. To make a function volatile, add an exclamation point (!) as the last character in the type_text argument.
For example, in Microsoft Excel for Windows, the following worksheet formula recalculates every time the worksheet recalculates:
CALL(«Kernel32″,»GetTickCount»,»J!»)
Top of Page
Modifying in Place — Functions Declared as Void
You can use a single digit n for the return type code in type_text, where n is a number from 1 to 9. This tells Microsoft Excel to modify the variable in the location pointed to by the nth argument in type_text, instead of returning a value. This is also known as modifying in place. The nth argument must be a pass-by-reference data type (C, D, E, F, G, K, L, M, N, O, P, or R). The DLL function or code resource must also be declared with the void keyword in the C language (or the procedure keyword in the Pascal language).
For example, a DLL function that takes a null-terminated string and two pointers to integers as arguments can modify the string in place. Use «1FMM» as the type_text argument, and declare the function as void.
Versions prior to Microsoft Excel 4.0 used the > character to modify the first argument in place; there was no way to modify any argument other than the first. The > character is equivalent to n = 1 in Microsoft Excel version 4.0 and later.
Top of Page
In this article, we will explaining how to implement a web service call from Microsoft Excel. The prerequisite for this? We must have web service toolkit installed.
EXCEL and the Web Services Toolkit
First, the Microsoft Excel environment has to be prepared. For use with Office 2003, Microsoft delivers the Web Services Toolkit 2.01 for download at:
http://www.microsoft.com/downloads/details.aspx?FamilyID=fa36018a-e1cf-48a3-9b35-169d819ecf18&DisplayLang=en
After the installation, the Web Services plug-in can be found in the Excel VB editor under Extras > Web Service References.
Excel is now ready to import WSDL files for the automatic creation of classes and data types to call the corresponding web services.
Creating the Web Service in SAP
The next step is to generate a web service from the SAP RFC function module and t expose it as WSDL file.
For example: convert RFC function module Z_ BAPI_XXXX_CREATEFROMDATA (any RFC enables function module) into a web service.
-
In SE37, go to Utilities->Create Web Service and follow the simple steps.
-
Go to transaction SOAMANGER and generate the WSDL.
Building the EXCEL Application
Now everything is prepared for the EXCEL application.
-
From the VB editor, choose «Web Service Reference» and mark the «Web Service URL» checkbox.
-
Type the full address of the WSDL file (e.g. C:Z_XYZ.xml).
-
A search result should appear (as shown in below snapshot).
If the WSDL file is correctly spelled and no search result appears, then it means WSDL file may be incorrect. One reason may be that in SAP, the input and output types are different (e.g. upper case for input fields, lower case for output fields).
-
Check the service and press the «add» button. The toolkit will parse the file and create type definitions and classes in the VB editor.
Wizard Results
After the upload of the WSDL file, the toolkit has added new classes of different types to the EXCEL project.
Some classes represent the table structures. In the example, the interface consists of the tables and other simple import structures leading to the structure classes (for the businesspartner tables e.g.:struc_BAPIBUS1037VBKAKOMCR).
Two other classes provide the objects for working with the web service. The method for calling the service in the example is in a class called
clsws_zcreatesalesactivity
And here the method for calling the service is implemented:
Public Sub wsm_Z_XXXX_CREATEFROMDATA (ByRef ar_BUSINESSPARTNER As
Variant, ByRef ar_GENERALDATA As Variant, ByRef ar_RETURN As Variant,
ByVal obj_SENDER As struct_BAPISENDER, ByVal str_TESTRUN As String)
Note that all table parameters are of type «variant», simple structures are of respective type «struc_xxx» and simple variables are of type «string».
In case of individual other applications, the classes and type definitions need to be checked: All tables and structure parameters from the function interface should appear as class modules named struc_xxx, including the type definitions for all fields. If not, check for restricted words in the data definitions of the WSDL file.
These fields are converted by the Web Services Toolkit in Excel according to
Public FROM_DATE As date
To avoid deserialization failed errors in the Web Service call, all «date» fields must be redefined to «string».
Public FROM_DATE As String
Calling the Service
To call the web service, an object needs to be created:
Dim SalesActivityWS As New clsws_zCreateSalesActivityS
Then all input tables need to be filled. This can be achieved for all tables as follows. First declare the table variables as ?Variant?. For example, for the businesspartners:
Dim ar_BUSINESSPARTNER as variant
Additionally, a variable of type struc_BAPIBUS1037VBKAKOMCR is needed to fill the input data. To account for more than one entry, the variable is defined as array.
Dim _StrucBusinesspartner(2) as struc_BAPIBUS1037VBKAKOMCR
Now the structure _StrucBusinesspartner can be filled from a corresponding EXCEL table or by use of VB input forms according to the needs. Finally, the input variables are transferred:
ar_BUSINESSPARTNER = _StrucBusinesspartner
And the service is called.
Call SalesActivityWS. wsm_Z_XXXX_CREATEFROMDATA ( ar_BUSINESSPARTNER,
ar_GENERALDATA, ar_RETURN, obj_SENDER, str_TESTRUN)
After the execution of the service, all ar_RETURN fields can be evaluated.
Possible Errors
If the deserialization error occurs, check again for remaining fields of type date or lower case field names.
Another error might read «too many open connections». This means the service could not log on to SAP. Check the user name and password provided in transaction SICF.
I am a VBA newbie, and I am trying to write a function that I can call from Excel cells, that can open a workbook that’s closed, look up a cell value, and return it.
So far I know how to write a macro like this:
Sub OpenWorkbook()
Dim path As String
path = "C:UsersUserNameDesktopTestSample.xlsx"
Dim currentWb As Workbook
Set currentWb = ThisWorkbook
currentWb.Sheets("Sheet1").Range("A1") = OpenWorkbookToPullData(path, "B2")
End Sub
Function OpenWorkbookToPullData(path, cell)
Dim openWb As Workbook
Set openWb = Workbooks.Open(path, , True)
Dim openWs As Worksheet
Set openWs = openWb.Sheets("Sheet1")
OpenWorkbookToPullData = openWs.Range(cell)
openWb.Close (False)
End Function
The macro OpenWorkbook() runs perfectly fine, but when I am trying to call OpenWorkbookToPullData(…) directly from an Excel cell, it doesn’t work. The statement:
Set openWb = Workbooks.Open(path, , True)
returns Nothing.
Does anyone know how to turn it into a working VBA function that can be called from Excel cell?
Data on a server can be modified by examining the records ‘client-side’ in Excel VBA, changing them as required, and saving them back to the server.
A more efficient way of doing this, particularly if the database is at a remote location and there’s a lot of traffic involved, is to do the work ‘server-side’. This exercise calls a stored procedure from Excel to categorise employees into age-ranges according to their dates of birth (i.e. 18-25 years, 26-35 years, etc.), without a copious exchange of data between the server and Excel.
This article assumes the reader has the Developer ribbon displayed and is familiar with the VBA Editor. If not, please Google “Excel Developer Tab” or “Excel Code Window”.
There are three elements to the exercise:
- A data table tblStaff within a database TestDB;
- A stored procedure spAgeRange;
- An Excel xlsm, which we’ll call xlsm. A sample Excel file can be found here
Data Table
Create a database in SQL Server called DBTest.
Set up the following columns for a table tblStaff.
Copy the following into the table:
2017/05/25 | 1 | Brown | J | 1946/12/02 | M | ||
2017/05/25 | 2 | Smart | A | 1976/03/26 | F | ||
2017/05/25 | 3 | Cruise | T | 1962/07/03 | M | ||
2017/05/25 | 4 | Lohan | L | 1986/07/02 | F | ||
2017/05/25 | 5 | Fredricksen | F | 1964/03/15 | M | ||
2017/05/25 | 6 | Snyder | L | 1968/07/05 | F | ||
2017/05/25 | 7 | Lipnicki | J | 1983/11/25 | M | ||
2017/05/25 | 8 | Hoover | S | 2002/12/08 | F | ||
2017/05/25 | 9 | Watson | E | 1990/04/15 | F |
Stored Procedure.
Run this script against TestDB to create the stored procedure:
USE [TestDB] GO /****** Object: StoredProcedure [dbo].[spAgeRange] Script Date: 2017/05/10 12:16:28 PM ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[spAgeRange] @PayrollDate varchar(50) AS BEGIN SET NOCOUNT ON; UPDATE tblStaff SET Age = CONVERT(int, DATEDIFF(day, DateOfBirth, GETDATE()) / 365.25, 0) WHERE tblStaff.PayrollDate = @PayrollDate Update tblStaff set AgeRange = '>56' where Age >= 56 and PayrollDate = @PayrollDate Update tblStaff set AgeRange = '46 to 55' where Age >= 46 and Age < 56 and PayrollDate = PayrollDate Update tblStaff set AgeRange = '39 to 45' where Age >= 39 and Age < 46 and PayrollDate = @PayrollDate Update tblStaff set AgeRange = '31 to 38' where Age >= 30 and Age < 39 and PayrollDate = @PayrollDate Update tblStaff set AgeRange = '25 to 30' where Age >= 25 and Age < 30 and PayrollDate = @PayrollDate Update tblStaff set AgeRange = '18 to 24' where Age >= 18 and Age < 25 and PayrollDate = @PayrollDate Update tblStaff set AgeRange = '<18' where Age < 18 and PayrollDate = @PayrollDate END
The stored procedure will saved under “Programmability” in the database.
Excel VBA
All that remains is to call the stored procedure from Excel, providing the PayrollDate parameter of “2017/05/25”. You will note I have simply data-typed PayrollDate as a string rather than wrestle with varying date formats. It is simple enough to convert a string to a date using the Convert function if PayrollDate is to be used for arithmetic purposes.
Create a new workbook. Open the VBA code window and insert a module.
From the code window’s Tools menu, reference the appropriate Active X 2.nn library to facilitate use of data objects.
Paste the following code into the Code window. This, once activated, will connect to SQL Server, as per the ConnectDatabase sub procedure
'All "public" in case the code is spread over several modules. Public connDB As New ADODB.Connection Public rs As New ADODB.Recordset Public strSQL As String Public strConnectionstring As String Public strServer As String Public strDBase As String Public strUser As String Public strPwd As String Public PayrollDate As String Sub WriteStoredProcedure() PayrollDate = "2017/05/25" Call ConnectDatabase On Error GoTo errSP strSQL = "EXEC spAgeRange '" & PayrollDate & "'" connDB.Execute (strSQL) Exit Sub errSP: MsgBox Err.Description End Sub Sub ConnectDatabase() If connDB.State = 1 Then connDB.Close On Error GoTo ErrConnect strServer = "SERVERNAME" ‘The name or IP Address of the SQL Server strDBase = "TestDB" strUser = "" 'leave this blank for Windows authentication strPwd = "" If strPwd > "" Then strConnectionstring = "DRIVER={SQL Server};Server=" & strServer & ";Database=" & strDBase & ";Uid=" & strUser & ";Pwd=" & strPwd & ";Connection Timeout=30;" Else strConnectionstring = "DRIVER={SQL Server};SERVER=" & strServer & ";Trusted_Connection=yes;DATABASE=" & strDBase 'Windows authentication End If connDB.ConnectionTimeout = 30 connDB.Open strConnectionstring Exit Sub ErrConnect: MsgBox Err.Description End Sub
Add a button to Sheet1 and assign it to sub procedure “WriteStoredProcedure”
The Results
Press the button, then examine tblStaff, which should be updated with ages and age ranges. The processing has taken place server-side.
Recovering corrupted workbooks
Should Excel crash it might well take your only copy of the workbook down with it. A good percentage of the time Excel is often unable to recover damaged workbooks; in such a case, all the work done since the creation of the workbook might be irrevocably lost, unless you have a tool to repair Excel xlsx or xlsm files.
Author Introduction:
Felix Hooker is a data recovery expert in DataNumen, Inc., which is the world leader in data recovery technologies, including rar repair and sql recovery software products. For more information visit www.datanumen.com
The default policy is preventing the CLR 4 from excuting the legacy code from the CLR 2 :
Set clr = New mscoree.CorRuntimeHost
To enable the legacy execution, you can either create the file excel.exe.config
in the folder where excel.exe
is located:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0"/>
</startup>
</configuration>
Or you can call the native function CorBindToRuntimeEx
instead of New mscoree.CorRuntimeHost
:
Private Declare PtrSafe Function CorBindToRuntimeEx Lib "mscoree" ( _
ByVal pwszVersion As LongPtr, _
ByVal pwszBuildFlavor As LongPtr, _
ByVal startupFlags As Long, _
ByRef rclsid As Long, _
ByRef riid As Long, _
ByRef ppvObject As mscoree.CorRuntimeHost) As Long
Private Declare PtrSafe Function VariantCopy Lib "oleaut32" (dest, src) As Long
''
' Creates a .Net object with the CLR 4 without registration. '
''
Function CreateInstance(assembly As String, typeName As String) As Variant
Const CLR$ = "v4.0.30319"
Static domain As mscorlib.AppDomain
If domain Is Nothing Then
Dim host As mscoree.CorRuntimeHost, hr&, T&(0 To 7)
T(0) = &HCB2F6723: T(1) = &H11D2AB3A: T(2) = &HC000409C: T(3) = &H3E0AA34F
T(4) = &HCB2F6722: T(5) = &H11D2AB3A: T(6) = &HC000409C: T(7) = &H3E0AA34F
hr = CorBindToRuntimeEx(StrPtr(CLR), 0, 3, T(0), T(4), host)
If hr And -2 Then err.Raise hr
host.Start
host.GetDefaultDomain domain
End If
VariantCopy CreateInstance, domain.CreateInstanceFrom(assembly, typeName).Unwrap
End Function
I’m not sure if this was just a coincidence or because I posted related question. SO showed me your question and I think I could also contribute something.
When working with VBA and DLL, most solutions that I’ve seen so far is telling me to register the DLL and make it com/gac visible. If you are doing this in your PC that’s absolutely fine but if you are distributing your VBA application, you don’t really want to install DLLs in their system. You might not have permission or you don’t really want to go through install/uninstall process or messing with referencing issues.
However you can load dlls dynamically using some windows APIs.
DLL
Now the question is how to access .NET dll from vba? if your clients have mixed os architecture x86 x64 you need to handle this accordingly. Lets assume we are working on 32bit office/Excel.
If you create a .NET dll and would like to access it from VBA it will throw an error message similar to «Can’t find the dll entry point». thankfully Robert Giesecke has created an abstract wrapper which will allow you to create simple DLL consumable via VBA.
A template can be found here.
All you have to do
- Create a new class project in visual studio
- Set the project platform either x86 for 32bit and otherwise
- Create your methods within a main class.
- create another class which will return your main class as object (is returning to vba)
- (follow the template from his website)
Lets assume you have followed his template and created a test method as following.
[ComVisible(true), ClassInterface(ClassInterfaceType.AutoDual)]
public class YOUR_MAIN_CLASS
{
[return: MarshalAs(UnmanagedType.BStr)]
public string FN_RETURN_TEXT(string iMsg)
{
return "You have sent me: " + iMsg + "...";
}
}
and your unmanagedexport class:
static class UnmanagedExports
{
[DllExport]
[return: MarshalAs(UnmanagedType.IDispatch)]
static object YOUR_DLL_OBJECT()
{
return new YOUR_MAIN_CLASS();
}
}
Preparing to access the dll from vba side
Add the DLL to your root folder:
#If VBA7 Then
Public Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr
Public Declare PtrSafe Function YOUR_DLL_OBJECT Lib "YOUR_DLL.dll" () As Object
#Else
Public Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal strFilePath As String) As Long
Public Declare Function YOUR_DLL_OBJECT Lib "YOUR_DLL.dll" () As Object
#End If
Now It’s all about loading the dll and creating & accessing objects it in vba.
that would be:
LoadLibrary (FN_APP_GET_BASE_PATH & "YOUR_DLL.dll")
dim mObj as object
set mObj = YOUR_DLL_OBJECT()
debug.print mObj.FN_RETURN_TEXT("Testing ..")
the output should be
"You have sent me: Testing ....."
Advantages
I personally don’t like installing and referencing dlls. By following above template, you don’t need to reference anything, you don’t need to install anything just load and work with your the DLL with full freedom.
NOTE: I assume the dll/.net code is yours and you can compile it again with above templates to.
I had success with above template and created a .NET non-blocking notifications for vba you can have a look here: non-blocking «toast» like notifications for Microsoft Access (VBA)
Here’s your solution, tested for .NET 2.0 and .NET 4.0, 32 bit and 64 bit, courtesy of Soraco Technologies.
The solution proposed below uses late binding and does not require registration of the .NET assemblies.
Declarations
Add the following declarations to your project:
#If VBA7 Then
Private Declare PtrSafe Function GetShortPathName Lib “Kernel32.dll” Alias “GetShortPathNameW” (ByVal LongPath As LongPtr, ByVal ShortPath As LongPtr, ByVal Size As Long) As Long
Private Declare PtrSafe Function SetDllDirectory Lib “Kernel32.dll” Alias “SetDllDirectoryW” (ByVal Path As LongPtr) As Long
Private Declare PtrSafe Sub LoadClr_x64 Lib “QlmCLRHost_x64.dll” (ByVal clrVersion As String, ByVal verbose As Boolean, ByRef CorRuntimeHost As IUnknown)
Private Declare PtrSafe Sub LoadClr_x86 Lib “QlmCLRHost_x86.dll” (ByVal clrVersion As String, ByVal verbose As Boolean, ByRef CorRuntimeHost As IUnknown)
#Else
Private Declare Function GetShortPathName Lib “Kernel32.dll” Alias “GetShortPathNameW” (ByVal LongPath As Long, ByVal ShortPath As Long, ByVal Size As Long) As Long
Private Declare Function SetDllDirectory Lib “Kernel32.dll” Alias “SetDllDirectoryW” (ByVal Path As Long) As Long
Private Declare Sub LoadClr_x64 Lib “QlmCLRHost_x64.dll” (ByVal clrVersion As String, ByVal verbose As Boolean, ByRef CorRuntimeHost As IUnknown)
Private Declare Sub LoadClr_x86 Lib “QlmCLRHost_x86.dll” (ByVal clrVersion As String, ByVal verbose As Boolean, ByRef CorRuntimeHost As IUnknown)
#End If ‘ WinAPI Declarations
' Declare variables
Dim m_myobject As Object
Dim m_homeDir As String
Initialization
You must initialize the m_homeDir variable to the path where the .NET assemblies are located.
For example, if you install the .NET assemblies in the same folder as the Excel or MS-Access files, you should initialize m_homeDir to:
Excel: m_homeDir = ThisWorkbook.Path
Access: m_homeDir = CurrentProject.Path
.NET Object Creation
Add the following code to your project.
Private Function GetMyObject(dllPath As String, dllClass As String) As Object
Dim LongPath As String
Dim ShortPath As String
LongPath = “\?” & m_homeDir
ShortPath = String$(260, vbNull)
PathLength = GetShortPathName(StrPtr(LongPath), StrPtr(ShortPath), 260)
ShortPath = Mid$(ShortPath, 5, CLng(PathLength – 4))
Call SetDllDirectory(StrPtr(ShortPath))
Dim clr As mscoree.CorRuntimeHost
If Is64BitApp() Then
Call LoadClr_x64(“v4.0”, False, clr)
Else
Call LoadClr_x86(“v4.0”, False, clr)
End If
Call clr.Start
Dim domain As mscorlib.AppDomain
Call clr.GetDefaultDomain(domain)
Dim myInstanceOfDotNetClass As Object
Dim handle As mscorlib.ObjectHandle
Set handle = domain.CreateInstanceFrom(dllPath, dllClass)
Dim clrObject As Object
Set GetMyObject = handle.Unwrap
Call clr.Stop
End Function
Private Function Is64BitApp() As Boolean
#If Win64 Then
Is64BitApp = True
#End If
End Function
Instantiate the .NET object
Now you are ready to instantiate your .NET object and start using it. Add the following code to your application:
m_homeDir = ThisWorkbook.Path
m_myobject = GetMyObject(m_homeDir & “yourdotnet.dll”, “namespace.class”)
The first argument is the full path to the .NET DLL.
The second argument is the fully qualified name of the requested type, including the namespace but not the assembly, as returned by the Type.FullName property.
Required DLLs
The solution requires deployment of 2 DLLs that are responsible for hosting the .NET CLR. The DLLs are expected to be deployed in the same folder as your Excel or MS-Access file.
The DLLs can be downloaded from Soraco’s web site: https://soraco.co/products/qlm/QLMCLRHost.zip
Licensing LGPL-2.1
We hereby grant you the right to use our DLLs as long as your application does not compete directly or indirectly with Quick License Manager. You can use these DLLs in your commercial or non-commercial applications.
Here is a canonical answer on the 3 main methods to call .Net from Excel (or VBA).
All three ways work in .Net 4.0.
1. XLLs
The 3rd party vendor Add-In Express offer XLL functionality, however its free and easy to use Excel-DNA the author is here https://stackoverflow.com/users/44264
Here is an extract from the Excel-DNA page: https://excel-dna.net/
Introduction
Excel-DNA is an independent project to integrate .NET into Excel. With Excel-DNA you can make native (.xll) add-ins for Excel using C#, Visual Basic.NET or F#, providing high-performance user-defined functions (UDFs), custom ribbon interfaces and more. Your entire add-in can be packed into a single .xll file requiring no installation or registration.
Getting Started
If you are using a version of Visual Studio that supports the NuGet Package Manager (including Visual Studio 2012 Express for Windows Desktop), the easiest way to make an Excel-DNA add-in is to:
Create a new Class Library project in Visual Basic, C# or F#.
Use the Manage NuGet Packages dialog or the Package Manager Console to install the Excel-DNA package:
PM> Install-Package Excel-DNA
Add your code (C#, Visual Basic.NET or F#):
using ExcelDna.Integration;
public static class MyFunctions
{
[ExcelFunction(Description = "My first .NET function")]
public static string SayHello(string name)
{
return "Hello " + name;
}
}
Compile, load and use your function in Excel:
=SayHello("World!")
2. Automation AddIns
This article by Eric Carter shows how to do it, the article is missing heaps of images so I am copy / pasting the entire article and have recreated the images for preservation.
REF: https://blogs.msdn.microsoft.com/eric_carter/2004/12/01/writing-user-defined-functions-for-excel-in-net/
Excel enables the creation of user defined functions that can be used in Excel formulas. A developer must create a special kind of DLL called an XLL. Excel also allows you to write custom functions in VBA that can be used in Excel formulas. Unfortunately, Excel does not support or recommend writing an XLL that uses managed code. If you are willing to take your chances that your XLL might not run in current or future versions of Excel, there are solutions available that enable this scenario—search the web for “managed XLL”.
Fortunately, there is an easier way to create a user defined function that doesn’t require you to create an XLL dll. Excel XP, Excel 2003, and Excel 2007 support something called an Automation Add-in. An Automation Add-in can be created quite simply in C# or VB.NET. I’m going to show you an example in C#.
First, launch Visual Studio and create a new C# class library project called AutomationAddin for this example.
Then, in your Class1.cs file, enter the code shown below. Replace the GUID with your own GUID that you create by using Generate GUID in the Tools menu of Visual Studio.
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace AutomationAddin
{
// Replace the Guid below with your own guid that
// you generate using Create GUID from the Tools menu
[Guid("A33BF1F2-483F-48F9-8A2D-4DA68C53C13B")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class MyFunctions
{
public MyFunctions()
{
}
public double MultiplyNTimes(double number1, double number2, double timesToMultiply)
{
double result = number1;
for (double i = 0; i < timesToMultiply; i++)
{
result = result * number2;
}
return result;
}
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(GetSubKeyName(type, "InprocServer32"), true);
key.SetValue("", System.Environment.SystemDirectory + @"mscoree.dll",RegistryValueKind.String);
}
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{
Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type, "Programmable"), false);
}
private static string GetSubKeyName(Type type, string subKeyName)
{
System.Text.StringBuilder s = new System.Text.StringBuilder();
s.Append(@"CLSID{");
s.Append(type.GUID.ToString().ToUpper());
s.Append(@"}");
s.Append(subKeyName);
return s.ToString();
}
}
}
With this code written, show the properties for the project by double clicking on the properties node under the project in Solution Explorer. Click on the Build tab and check the check box that says “Register for COM Interop”. At this point you have an extra step if you are running on Windows Vista or higher. Visual Studio has to be run with administrator privileges to register for COM interop. Save your project and exit Visual Studio. Then find Visual Studio in the Start menu and right click on it and choose “Run as Administrator”. Reopen your project in Visual Studio. Then choose “Build” to build the add-in.
Now launch Excel and get to the Automation servers dialog by following these steps:
-
Launch Excel and click the Microsoft Office button in the top left corner of the window.
-
Choose Excel Options.
-
Click the Add-Ins tab in the Excel Options dialog.
-
Choose Excel Add-Ins from the combo box labeled Manage. Then click the Go button.
-
Click the Automation button in the Add-Ins dialog.
You can find the class you created by looking for AutomationAddin.MyFunctions in the list of Automation add-ins:
Now, let’s try to use the function MultiplyNTimes inside Excel. First create a simple spreadsheet that has a number, a second number to multiple the first by, and a third number for how many times you want to multiply the first number by the second number. An example spreadsheet is shown here:
Click on an empty cell in the workbook below the numbers and then click on the Insert Function button in the formula bar. From the dialog of available formulas, drop down the “Or select a category” drop down box and choose “AutomationAddin.MyFunctions.
Then click on the MultiplyNTimes function as shown here:
When you press the OK button, Excel pops up a dialog to help you grab function arguments from the spreadsheet as shown here:
Finally, click OK and see your final spreadsheet as shown here with your custom formula in cell C3.
3. Calling .Net from Excel VBA
REF: Calling a .net library method from vba
Using the code from the Automation.AddIn project we can easily call the MultiplyNTimes function from Excel VBA.
First Add a reference to the DLL from Excel, to do this you will need to be in the VB Editor. Press Alt + F11, then click Tools menu and References:
Select the AutomationAddIn DLL:
Add VBA code to call the .Net DLL:
Sub Test()
Dim dotNetClass As AutomationAddIn.MyFunctions
Set dotNetClass = New AutomationAddIn.MyFunctions
Dim dbl As Double
dbl = dotNetClass.MultiplyNTimes(3, 2, 5)
End Sub
And hey presto!
Please note if you’re working with Classes in C# you will need to mark them with ClassInterface, with an Interface marked with ComVisible = true: Use CLR classes from COM addin in Excel VBA?
Finally there are some excellent MSDN articles about Excel and .Net by «Andrew Whitechapel» — google them
As part of my research, I wanted to combine the speed of C with the ability Excel provides to easily visualize and process substantial quantities of information. From the documentation and message boards scattered around the internet, along with a healthy does of experimentation, I was able to get it working quite well. What previously took 2 hours using only Excel and VBA (even with all the tricks I’ve learned over the years to make Excel about as fast as possible), now takes just seconds with the C functions doing most of the work. If the task is something you need to do a few hundred times, it can now be completed in an hour instead of a month. I prepared step-by-step instructions for myself so that I’ll remember how to do it in the future and figured I’d put them online to help anyone else looking to do the same thing. To do everything described below I used Visual Studio 2008 (hereinafter VS08) and Excel 2010 64-bit (hereinafter Excel) on Windows 7 64-bit. Examples are available for download. An example of how to use the same DLL to call the C functions from Mathmatica (using version 9) is also included near the end of the page.
Update: I recently switched to Visual Studio 2012 and referred back to these notes when making changes to a C DLL I’d originally written using VS08. Some of the screenshots look different, but everything described below also work using VS12.
Links to the sections on this page:
-
Debugging the DLL using VS08
-
Release build/version (or more generally, a version that will work on other computers)
-
C function with array arguments that «returns» array
-
Console for displaying output
-
Downloads
Creating a C DLL and using it in Excel
Creating a C DLL and using it in Excel
-
-
Open VS08
-
Create a new project (File>New>Project)
-
Select «Win32 Project»
-
Name: “squareDLL” (or whatever you want)
-
I let it “Create directory for solution”
-
-
-
-
-
Click OK
-
Click Next
-
Select Application Type: DLL
-
Select Additional Options: Empty Project
-
Click Finish
-
-
-
-
Add new empty .c file (or download it here)
-
Right-click the Source Files folder in the Solution Explorer (on the left side of the screen by default) and select Add>New Item
-
Select “C++ File(.cpp)”
-
Name: “square.c” (or whatever you want) (or .cpp for C++ file, in which case you’ll have to write the function slightly differently)
-
Click Add
-
-
-
-
Type the contents of the C function
-
As an example, I’m using: double _stdcall square (double *x) { return *x * *x; }
-
The first «double» is the return type of the function
-
The «(double *x)» means the argument x is a pointer to a double (in VBA we’ll pass the argument «byRef»)
-
The function body, “return *x * *x;”, has a lot of * in it. Each “*x” is because the x is a pointer and we want to multiply the value of x (you could also use x[0] instead of *x). The middle * is just multiplication.
-
-
You can also include files like the one at the top of the screenshot, but we don’t need any for this, so I commented it out («//#include <stdio.h>»)
-
If you’re creating a C++ file instead (e.g., «square.cpp»), then the function would be: double _stdcall square (double &x) { return x * x; }
-
-
-
-
Add a definition file (or download it here)
-
-
Right-click the Source Files folder in the Solution Explorer and select Add>New Item
-
Select “C++ File(.cpp)»
-
Name: “defFIle.def” (you can change the defFile part, but need the .def extension)
-
Click Add
-
-
-
-
-
Type the contents of the definition file
-
File contents:
-
LIBRARY «square»
-
EXPORTS
-
squareForEXL = square
-
-
-
-
-
-
Comments:
-
I’m not sure what the «square» on the first line does since the name of the DLL ends up being the project name (squareDLL). I think there are settings somewhere that deal with this.
-
«squareForEXL» is the name of the function in Excel. It can be the same as the name of the function in the C file («square»). I just made it different as an example.
-
If you want to have more than one function available in Excel, you can include each additional function on its own line at the bottom (e.g., «myFunc2 = myFunc2» on a line after «squareForEXL = square»)
-
-
-
-
-
Tell the compiler to use the definition file
-
Right-click the project name “squareDLL” and select Properties to open the project properties
-
Select Configuration Properties>Linker>Input
-
Next to Module Definition File, type: defFile.def
-
Click Apply
-
Click OK
-
-
-
-
Compile (F7)
-
If you’re using 32-bit Excel (I think on either 32-bit or 64-bit OS), then the DLL is ready to go. If you’re using 64-bit Excel, then you need to set it up to work in 64-bit Excel.
-
Right-click the project name «squareDLL» and select Properties to open the project properties
-
Select Configuration Properties>General
-
Mine starts off looking like this
-
-
-
-
-
Click the button near the top that says «Configuration Manager…»
-
Where it says «Active solution platform:» and Win32 is selected, click the arrow and select «New»
-
Under “Type or select the new platform:” select «x64»
-
If x64 is not an option, it wasn’t installed when you installed VS08 and you need to install it now.
-
Close VS08
-
Instructions can be found online. For convenience, I’ll include these instructions here
-
Go to Add or Remove programs in the Control Panel
-
Select Microsoft Visual Studio 2008
-
Click Uninstall/Change
-
Click Add or Remove Features
-
Under «Select features to install», expand Language Tools > Visual C++
-
If the box «x64 Compiler and Tools» is not checked, check it, then click Update. If the box is already checked, I have no idea what to suggest—Google it.
-
After you’ve done that, restart your computer and come back to this step. x64 should now be there
-
When I tried to do this on my laptop for the first time, I followed these steps. When I tried to call the DLL from Excel (described below), I received «File not found» and «Can’t find entry point» errors. I found various suggestions online (e.g., going to the project setting Configuration Properties>Linker>General and changing «Enable Incremental Linking» to no), but nothing helped. I used the program Dependency Walker and discovered that the problem wasn’t with my DLL but with a different one, msvcm90.dll. I uninstalled VS08 and re-installed it. This time, I chose the custom install option and made sure that the «x64 Compiler and Tools» part was installed to start with this time. I also went to add or remove programs and did a repair of my Office 2010. I don’t know what the problem was or if there was an easier way to fix it, but after that, it worked.
-
-
Let it «Copy settings from:» Win32
-
Select «Create new project platforms»
-
This is how the original Configuration Manager screen looks (background) and what the screen looks like after you select new and fill in these things (foreground)
-
-
-
-
-
Click OK
-
After that, the Configuration Manager screen looks like this (there’s a note on Release build below)
-
-
-
-
-
Click Close
-
After that, the «Platform:» will say «Active(x64)»
-
-
-
-
Compile again (F7)
-
Open Excel (or download an example here )
-
Open VBA (alt-F11)
-
Insert a new module
-
In the module, declare the C function so that it can be used by VBA and Excel
-
In 64-bit Excel: «Private Declare PtrSafe Function squareForEXL Lib «C:UsersJonDocumentsVisual Studio 2008ProjectssquareDLLx64DebugsquareDLL.dll» (ByRef x As Double) As Double»
-
-
-
-
-
In 32-bit Excel: «Private Declare Function squareForEXL Lib «C:UsersJonDocumentsVisual Studio 2008ProjectssquareDLLDebugsquareDLL.dll» (ByRef x As Double) As Double»
-
Obviously change the path to the location of your DLL
-
You could put the entire «Declare» statement on one line instead of using the underscore after the function name
-
The 64-bit Excel version has 2 main changes
-
«PtrSafe» basically tells VBA that the function is safe for 64-bit
-
VS08 changes the DLL location to the x64 folder, so make sure the path is to the 64-bit DLL
-
-
A few comments on the «Private» before the «Declare»
-
-
-
-
-
-
The Private keyword is not required. In fact, the examples I’ve seen online don’t use it
-
Without the Private keyword you could use squareForEXL as a worksheet function (e.g., «=squareForEXL(E1)»)
-
However, when you use squareForEXL as a worksheet function, it results in errors. On my desktop, it returns the correct result (e.g., «= squareForEXL(10)» yields 100) but then gives an «Out of Stack Space» error, either at some point when calling the function or when Excel is closed. On my laptop, it returns an incorrect result (e.g., «= squareForEXL(10)» yields 0). On both, Excel sometimes crashes.
-
If you debug this, the value in VS08 is not what it should be. My guess is that when the argument comes from the worksheet, the C function doesn’t receive a pointer to a double like it’s expecting.
-
To solve this problem, I use an intermediate function in VBA. We’re already using the Declare statement as an interface for the C function in the DLL. This just adds another step in VBA in between the C function and the worksheet. Instead of calling squareForEXL as a worksheet function, we call the VBA function squareOnWorksheet. The VBA function squareOnWorksheet takes a double as an argument, calls squareForEXL using this double as an argument, and then returns the value it gets back from squareForEXL. This way squareForEXL gets the double it is expecting and the worksheet gets the result it is expecting.
-
Doing this, the worksheet function squareOnWorksheet always returns the correct value and there are no errors or crashes.
-
The Private keyword makes squareForEXL Private to the VBA module so that you cannot (accidentally or otherwise) use squareForEXL as a worksheet function.
-
-
-
-
-
Use the function
-
In VBA, you can use «squareForEXL(10)» and it should return 100 (see function «useSquareInVBA()» in screenshot above). Or you can use a VBA double variable as an argument.
-
In Excel, you can type «=squareOnWorksheet(10)», the intermediate VBA function described above, and the cell value will be 100
-
-
-
-
Save this file if you want to use it in the next part about debugging
-
-
The C function, definition file, and Excel file described above are available for download here.
Debugging the DLL using VS08
Debugging the DLL using VS08
-
-
Do the preceding steps to create the DLL and call it from Excel
-
Set up debugging in VS08
-
Right-click the project name “squareDLL” and select Properties to open the project properties
-
Select Configuration Properties>Debugging
-
In the dropdown list next to “Command”, select Browse (or you can type the file path manually)
-
Find your Excel program (for me, it’s «C:Program FilesMicrosoft OfficeOffice14EXCEL.EXE»)
-
Click Apply
-
-
-
-
-
Now select Configuration Properties>C/C++>Browse Information
-
Next to «Enable Browse Information» select «Include All Browse Information (/FR)»
-
-
-
-
-
Click Apply
-
Click OK
-
-
-
-
Add a break point to the function. This isn’t necessary. It’s just so that it stops in VS08 while running so you can see it’s working
-
-
-
Press F5 to start debugging
-
It might give a message like this:
-
-
-
-
-
That’s fine. Just click yes (and you can select «Don’t show this dialog again» if you want)
-
An instance of Excel opens
-
Open the Excel file you saved before (or do the VBA steps above to create a new one that calls the function)
-
Do something to make the function re-calculate (e.g., run a VBA procedure that calls the function, change the value in the cell that is used as the input, force recalculation with ctrl-alt-F9, press F2 in the cell with the formula and then press enter)
-
It should take you back to VS08 to the break point you set
-
If you put your mouse over the variable x, you should be able to see the value. Actually, it will show you the pointer value, but if you click the little “+” it will show you the value. Or you can add a line to the C file such as «double temp=*x;» before the break point and then put your mouse over the variable «temp» which has the value of x. Or you can add a watch.
-
-
Release build/version (or more generally, a version that will work on other computers)
Release build/version (or more generally, a version that will work on other computers)
Everything described above was for a debug build/version. The release build works on the computer you used to write the DLL, but doesn’t work on all other computers. To fix this, do the following
-
-
Under Configuration Properties>C/C++>Code Generation, change «Runtime Library» from «Multi-threaded DLL (/MD)» to «Multi-threaded (/MT)».
-
-
I added the above screenshot after switching to VS12 (from VS08), so it might not look identical. But I did do this using VS08 and it worked. It might not solve every problem with building a Release version and/or using the DLL on other computers, but it worked for me.
C function with array arguments that «returns» array
C function with array arguments that «returns» array
Many functions you’d actually want to implement in this way will have array arguments and/or should return arrays. The implementation below is not the most robust implementation available (e.g., it doesn’t check for or handle any errors, it «returns» an array as described below). There are more formal ways of doing this that involve Excel XLL add-in files (see links at the bottom), but these are significantly more involved (i.e., would require more than part of an afternoon to learn how to do). However, this implementation is quite easy. It requires little more than the steps described above for the simple «square» function. Everything described below is available for download here.
-
-
Everything about creating the DLL and using it in Excel is the same as the steps above. So create a DLL as described above. Or you can use the one you created before and add a new function to the C file (don’t forget to also add it to the definition file). This can be done with or without the debugging described above. I created a new project called «arrayExcelCDLL» with C file «arrayFunc.c» (available below) and definition file «defFile.def» (only the definition file for «square» is available below, but you just have to change the names).
-
Write contents of C function
-
The C function looks like this
-
-
-
-
-
The return type is int. It returns 0 if it successfully gets to the end. So while the function «returns» an array of results, it’s not via the actual return value.
-
The first argument, «double* dIn», is a pointer to a double that we’ll treat like an 1 dimensional array of doubles. I loop through it with a double for loop as though it is a 2 dimensional array with dimensions given by «int* iSizeIn». It comes from a 1 or 2 dimensional array in Excel. It could be a non-array double in Excel, in which case the array is 1×1. To pass the pointer to the double array from VBA, we use the first element of the VBA double array as the argument.
-
The second argument, «double* dOut», is a pointer to a double that we’ll treat like a 1 dimensional array of doubles, similar to dIn. However, we’ll use dOut to «return» results. It comes from a 1 or 2 dimensional array in Excel with dimensions given by «int* iSizeOut». The argument that is passed from excel is the first element of a double array (or a non-array double that’s 1×1). It is passed by reference, so what is received by the C function is a pointer to the start of the location in memory for this array. We can write to the memory locations occupied by the array just as if it was an array we created in the C function. When the function returns to Excel, the values of the double array in VBA will be whatever we set in the C function. So while we’re not actually returning an array of results, in practice we’re «returning» an array of results. It might not earn you many style points from a professional programmer, but it works and it’s a lot easier than the other methods I’m aware of that use XLL files.
-
The function itself simply takes each element of dIn and stores the value multiplied by 10 in dOut to «return» to Excel. A real function could obviously do something more complicated. The size of dOut does not have to be the same as the size of dIn, so the function can be modified to achieve much more general goals.
-
-
-
-
Write the VBA code to use the C function
-
To use the C function in the DLL, you need to declare it similarly to what we did above with the «square» function. In 64-bit Excel, this is accomplished by: «Declare PtrSafe Function useArray Lib «C:UsersJonDocumentsVisual Studio 2008ProjectsarrayExcelCDLLx64DebugarrayExcelCDLL.dll» (ByRef dIn As Double, ByRef dOut As Double, ByRef iSizeIn As Long, ByRef iSizeOut As Long) As Long»
-
The function is called by: «iWasError = useArray(dVals(1, 1), dRet(1, 1), iDimsIn(1), iDimsOut(1))»
-
«iWasError» will become 0 if the function returns successfully
-
«dVals(1, 1)» is the first element of the double array that holds the arguments, corresponding with dIn
-
«dRet(1, 1)» is the first element of the array that will be modified to hold the results, corresponding with dOut
-
«iDimsIn(1)» is the 1×2 array that holds the height and width of dVals
-
«iDimsOut(1)» is the 1×2 array that holds the height and width of dRet
-
-
The example file (available below) takes values from a range starting in cell A3 on the worksheet, calls the C function, and then puts the returned results (the original values multiplied by 10) in the cells to the right of the original values.
-
It is currently set up with a 10×10 array with the numbers 1 through 100 and takes between 0.001 and 0.01 seconds on my computer. I’ve also tested it with a single value in cell A3 or with 10 columns x 100,000 rows of values. In the later case with 1 million values, it takes between 0.5 and 0.8 seconds on my computer (and only about 1 to 1.3 seconds on my old laptop).
-
-
-
The C function, definition file, and Excel file described above are available for download here.
Console for displaying output
Console for displaying output
If you want a console to display output or to help with debugging, you can open one from the C DLL.
-
-
Include «#include <stdio.h>» at the top of the DLL
-
At the start of the function, include the following lines of code
-
AllocConsole()
-
freopen(«CONIN$», «r», stdin);
-
freopen(«CONOUT$», «w», stdout);
-
freopen(«CONOUT$», «w», stderr);
-
-
Then in your code you can do things like: fprintf(stdout, «iVar: %dn», iVar);
-
To make the console stay open so that you can see the output, at the end include: getchar();
-
Close the console using: FreeConsole();
-
Calling C DLL from Mathematica
Calling C DLL from Mathematica
On this page, I describe how to call the C functions in the DLLs above from Mathematica.
To figure out everything above, I started from various examples I found online and then experimented. I’ll provide links to a few here in case you want to read more and to give credit where credit is due.
-
-
If you’d like to learn the first step of creating the «square» function by watching a video, watch this video on youtube. This is where I first learned the general technique so most of the steps are the same. The main exceptions are the part about 64-bit excel and the way I call the function from the worksheet using the intermediate VBA function to avoid the errors I got doing it the way shown in the video. If you click on his name, he also has a video about debugging.
-
I figured out how to do the example with array arguments and results through experimentation, but after figuring it out, I came across this example which does something very similar using C++.
-
Microsoft has documentation available here which is mostly about developing XLLs, but it can be useful for this and other topics with VBA.
-
There is a book by Steve Dalton. The newest edition I found was called Financial Applications Using Excel Add-in Development in C/C++. The link is just to a goolge search. The book is mostly about XLLs, but it is mentioned on many message boards with information about other useful topics.
-
There are many others—Google it. I’m not sure how we learned any of this before message boards, blogs, and the rest of the internet. It certainly took longer than an afternoon.
-
The square example is available for download here.
The array example is available for download here.
How can I call a module written in Excel by clicking on an ActiveX control in a worksheet?
Excellll
12.5k11 gold badges50 silver badges78 bronze badges
asked May 18, 2012 at 12:39
It’s not entirely clear what you’re asking, but I understand this to be your problem:
You have an ActiveX Control that runs on a click event. The VBA for this is only called by the button click and cannot be called from any other Sub, but you would like to be able to call this code from another module.
I don’t believe you can do that, but there is a better approach to the problem. Place the code for your ActiveX control in a new Sub in a module. Then replace the code for the button click event with the following:
Private Sub CommandButton1_Click()
Call NewSub
End Sub
Where NewSub
is the name of your new Sub. This should allow you to do what you wanted.
answered May 18, 2012 at 16:41
ExcellllExcellll
12.5k11 gold badges50 silver badges78 bronze badges
The code for an ActiveX control, such as a button_click on a worksheet, may be called from other subs, even on other modules. Simply use the keyword «Public» to describe the ActiveX control sub instead of «Private». Then call the sub with a statement such as Call Sheets(mySheetName).myButtonName_Click
.
answered Sep 4, 2013 at 20:49
To call subroutine located in ThisWorkbook from SHeet1:
Do that:
Call ThisWorkbook.ParseText
Where definition:
Public Sub ParseText()
answered Apr 27, 2018 at 11:40
Overview
All the data from a stSoftware server can be fetched via the standard ReST API, all the standard ACLs and validation rules are applied whether the data is access via the standard screens or via the ReST API
Example Excel Spread Sheet
Click here to download an example Excel spread sheet which shows how to fetch data from an ST Server into Excel.
How to use
1. Open spreadsheet and click «Enable Macros».
2. Click «add-ins» menus
3. Click «Login» icon
4. Enter connection details
Enter the connection details for your own server or use one of the demo systems by using the host https://demo2.jobtrack.com.au and the user name user with the password user
Please note the demo servers are reset daily ( don’t store anything you want to keep).
5. Click on the query button
6. Enter the fields, class and filer for the data to be fetched.
There are a number of predefined templates which can be chosen or enter the fields «Class», «Fields» and «Where» directly.