I would like to create a new Excel function (user Defined Function), for that i did the same steps as in this link: https://excel-dna.net/
I created a class Library Project
I installed the package ExcelDna.Integration
I created a method sayHello
But when i try to call my function from a cell in excel (i put =sayHello("World"), the function didn't appear, it seems it's not added to excel functions.
is there some missing steps? how can i make my function appear to be able to use it ?
You should install the package "ExcelDna.AddIn" to make the add-in (that will set up the add-in including the important .dna file, and also bring in the "ExcelDna.Integration" reference library).
So the steps would be:
Create a new C# Class Library project (targeting .NET Framework not .NET Standard)
Install the ExcelDna.AddIn package
Add some code, e.g.
public static class MyFunctions
{
public static string SayHello(string name) { return "Hello " + name; }
}
Press F5 to compile and load the add-in in Excel
(Note that on some Excel installations, the Debug setting for the project get an extra %1 in the executable path - just remove this from the end if you get an error when debugging)
The best support for Excel-DNA is the Google group at https://groups.google.com/forum/#!forum/exceldna
Related
I am writing a C# DLL which must be COM visible as it's main use case will be embedded into Microsoft Excel VBA (I know). Whilst developing I have been using Visual Studio's "Register for COM Interop" checkbox and having the process done for me. This has been working fine on my PC as I am able to get valid outputs in Excel, however now I am trying to register the DLL on client machines (manually) and I seem to be having issues with making valid calls as Excel only returns !VALUE.
This following has been my process:
AssemblyInfo.cs:
[assembly: ComVisible(true)]
Class1.cs:
namespace ManualRegister
{
public class Class1
{
public string test()
{
return "Working!";
}
}
}
Copy ManualRegister.dll into SysWOW64
Register.bat:
cd/
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe ManualRegister.dll /tlb:ManualRegister.tlb /codebase
pause
Adding reference to VBA module.
VBA Code:
Function test()
Dim object As New ManualRegister.Class1
test = object.test()
End Function
VBA error:
Can anyone see what step I'm missing / doing wrong?
(I have also tried specific CPU architecture builds to no avail)
Goal: Create a C# Assembly called TestDLL.dll that can be installed to any computer such that MS Access VBA can use it via COM.
Environment:
Windows 7 64-bit.
MS Office Professional Plus 2010 Version: 14.0.1753.5000 (64-bit).
Visual Studio 2010 Professional.
TestDLL.dll assembly code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace TestDLL
{
[ComVisible(true)]
[Guid("7CAAEF3F-F867-445B-B078-5837A833620A")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IGreeting
{
string SayHello();
}
[ComVisible(true)]
[ProgId("TestDLL.Greeting")]
[Guid("73D4187A-F71D-4E45-832A-6DD9F88CC59B")]
[ClassInterface(ClassInterfaceType.None)]
public class Greeting : IGreeting
{
[ComVisible(true)]
public string SayHello()
{
return "Hello, World!";
}
}
}
A WinForms project added to the solution successfully calls the SayHello() method.
TestDLL project properties:
Application / Target Framework - .NET Framework 4
Application / Assembly Information / Make assembly COM-visible: false (I only want certain public classes within the assembly to be COM-visible, not ALL public classes. Even though for this demo there's just one class and I do want it to be COM-visible. The code above should have taken care of that.)
Application / Assembly Information / Title and Description and Company and Product are all "TestDLL".
Build / Platform: Active (any CPU)
Build / Platform target: x86
Build / Register for COM interop: false (I don't want it to work on MY computer only but ALL computers. Thus I want to register the assembly when it is INSTALLED, not when it is BUILT.)
Signing / Sign the assembly: false (I want the assembly to live in the install folder, not in the GAC.)
A peek at AssemblyInfo.cs reveals:
[assembly: ComVisible(false)]
[assembly: Guid("6bf701f9-3953-43bb-a8af-1bdf7818af3c")]
The assembly is built.
Then a type library is created using the Visual Studio Command Prompt (run as Administrator) with this command:
tlbexp "C:\(path)\bin\Release\TestDLL.dll" /win32 /out:"C:\(path)\bin\Release\TestDLL.tlb"
A Visual Studio Installer project called SetupTestDLL is added to the solution.
On its File System tab, Application Folder, TestDLL.dll is added. This automatically also adds TestDLL.tlb.
Right-clicking TestDLL.dll in that Application Folder allows opening a properties window.
There, Register: vsdraCOM
When right-clicking TestDLL.tlb in that Application folder to get the properties window:
Register: vsdrfCOM
(I'm guessing that vsdraCOM means register the assembly and vsdrfCOM means register a file for COM.)
One more file is added to the Application folder: TestDLL.pdb.
SetupTestDLL is built.
Browsing to its output folder, reveals setup.exe and setupTestDLL.msi.
Right-click setup.exe and Run as administrator.
A dialog box displays the correct install path and the correct "Install for everyone" option.
The install completes successfully.
In the Control Panel / Programs and Features, TestDLL is now listed. Its publisher is listed as "XYZ". Where did that come from? Evidently from the "Manufacturer" property of the SetupTestDLL project's property window. I created that value only there in the entire solution.
In C:\Program Files (x86) there is now an "XYZ" folder, under which is a TestDLL folder, and in that are the three files.
Launch MS Access. Open an existing database and its existing code module.
From the Access code window toolbar, choose Tools / References.
TestDLL is found in the Available References listbox. Click its check box and click OK.
Click the Object Browser button on the code window toolbar.
is selected in a dropdown list. Change it to TestDLL.
The class "Greeting" is shown with its method "SayHello". So far, so good.
Close the Object Browser.
Create this procedure in the code module and try to run it.
Public Sub Test2()
' Dim o As New TestDLL.Greeting
' The above is early binding. It should also work
' since we set a reference.
Dim o As Variant
Set o = CreateObject("TestDLL.Greeting")
' The above is late binding.
Debug.Print o.SayHello()
Set o = Nothing
End Sub
Result:
Whether early or late bound,
ActiveX Component can't create object.
What's wrong?
I was just going to add a comment, but I don't have enough reputation points so I'll just post this as an answer and remove it if necessary.
I'm not familiar with Visual Studio Installer projects, so I'm not sure if it is registering the assembly correctly. Have you tried using regasm to register TestDLL? Something like:
regasm /codebase TestDLL.dll /tlb:TestDLL.tlb
64-bit MS Office cannot use a 32-bit COM DLL early bound, but with a reg hack involving DLLSurrogate, it can use it late-bound. I got that to work.
STEP 1: creating Excel 2010 add-in
I created a new project, Excel 2010 add-in, .Net 4 framework
I added a class file to it "Name.cs", interface "iName.cs" and added a function to it
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface iName
{
string getName();
}
[ClassInterface(ClassInterfaceType.None)]
public class Name
{
public string getName()
{
return "Hello";
}
}
STEP 2: Configuring build events
I configured the build events of the pro
"%Windir%\Microsoft.NET\Framework\v4.0.30319\regasm" /codebase /tlb
"$(MSBuildProjectDirectory)\$(OutputPath)$(AssemblyName).dll"
This will register the Dll so that it will be available in the references column in the Excel
STEP 3: Adding reference in Excel macro
I created a module, in the tools-> reference I added the NameProvider (name of that assembly/project) add-in that is available after I built the Excel add-in project
I tried to create an object for that added reference
Public Sub test()
Dim nameObj as NameProvider.Name
Dim name as string
Set nameObj = new NameProvider.Name 'error 429 occurs here
name = nameObj.getName() 'getName function automatically comes after .
End Sub
For Office 64bit you need to compile your assembly as x64 compatible, and register it with the 64bit framework by using the regasm from the Framework64 folder.
"%Windir%\Microsoft.NET\Framework64\v4.0.30319\regasm" /codebase /tlb
"$(MSBuildProjectDirectory)\$(OutputPath)$(AssemblyName).dll"
%Windir%\Microsoft.NET\Framework\v4.0.30319\regasm -> %Windir%\Microsoft.NET\Framework64\v4.0.30319\regasm
i have created a C# dll file on my machine as shown below:
namespace myDLL
{
public class myClass
{
public string myFunction()
{
return "I am Here";
}
}
}
then i created a tlb file with "tlbexp" command,
then i used the "regasm" command n registered this dll on my machine.
When i created an object of type myClass on my machine using VBScript, everything is working fine... here i used the CreateObject() method as shown below:
Set myObj = CreateObject("myDll.myClass")
Now i want to create an object of type myClass from VBScript that is running on another machine, how can i do this. please help me how can i access that dll file, am using the CreateObject() function as shown below:
Set HD = CreateObject("myDll.myClass","myMachineName")
now am getting error as "permission denied".
It appears that this is supported if the assembly is built with as COM visibility enabled.
Is it possible to execute a .NET assembly(dll) from vbscript?
By the way, I was pretty delighted to find out that there is a JScript compiler for .NET which allows one to write .NET code using JScript and also to target other .NET assemblies but unfortunately I haven't found anything similar for VBScript.
I have a simple class library written in c#.
using System;
namespace TestDll
{
public class Test
{
public string HelloWorld
{
get
{
return "Hello World";
}
}
}
}
My question is how can I call this HelloWorld function from Microsoft Office Visual Basic (which I think is VB6)?
My first step was to add the DLL as a reference - but on browsing and selecting the compiled DLL the message "Can't add a reference to the specified file." was thrown.
Can anyone point me in the right direction as to why/how to get this working?
Thanks in advance SO!
You can't access a static member via COM interop. In fact your code doesn't even compile, the method should be in a class. Here is how you can do it:
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("01A31113-9353-44cc-A1F4-C6F1210E4B30")] //Allocate your own GUID
public interface _Test
{
string HelloWorld { get; }
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("E2F07CD4-CE73-4102-B35D-119362624C47")] //Allocate your own GUID
[ProgId("TestDll.Test")]
public class Test : _Test
{
public string HelloWorld { get { return "Hello, World! "; } }
}
The project properties Build tab, select Register for COM interop. So you can see the results quickly. To install the dll on another machine you need to use regasm.
To then consume this:
Dim o : Set o = CreateObject("TestDll.Test")
MsgBox o.HelloWorld
You can also reference the dll and use early binding:
Dim o As TestDll.Test
Set o = New TestDll.Text
MsgBox o.HelloWorld
And to expand on registering the DLL on different computers.
Once you compile and build the above code on your development machine, if you have
The project properties Build tab, select Register for COM interop.
your Visual Studio output folder (usually bin\Debug) where the compiled *.dll is found will also have a *.tlb file.
This *.tlb file is a 'Type Library'. And is needed by the client machine to understand the different 'Types' in your *.dll and to basically tell the client machine how to use it.
By setting the above 'Register for COM interop' -- aswell as a *.tlb file being produced, the assembly(dll) is registered on your machine, and is therefore accessible.
In VBA you can now add this file as a reference by
VBA Editor -> Tools -> References -> Browse -> Select
this will allow you to then declare the classes found in your library.
Dim TestClass As Test
Set TestClass = New Test
MsgBox TestClass.HelloWorld
HOWEVER - if you want to then use your dll on a different client machine, you will have to use regasm.exe - to register the assembly(dll) on that machine.
This can be done by the command line,
regasm.exe
in this case
regasm.exe TestDll.dll
once you have registered the assembly on the new client machine, you will be able to access it by again adding a reference to its *.tlb
Hope this helps!
Just wanted to comment that in Visual Studio 2008, to get the .tlb file generated you must also go under the Application | Assembly Information and select "Make Assembly COM visible". Took me a while to find that, so hope it helps others out.
To add to AnthonyWJones's good answer, you'll also need to register your DLL using Regasm.exe which adds the necessary registry entries.