I am trying to follow the simplest example at the Excel-DNA.net front page to create a simplest UDF for Excel. My code builds correctly, except it builds into dll instead of xll. How do I build it into an xll file?
I literally follow the example from the page (copy pasting it here)
Create a new Class Library (.NET Framework) 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 ExcelDna.AddIn
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!")
All is fine, except it builds into DLL...
The most likely reason why your project is not creating an .xll is because the library you created is targeting ".NET Standard" and not ".NET Framework". The project file format used when targeting ".NET Standard" is not compatible with the NuGet package.
Maybe you can check that again when creating the project, paying particular attention to the "... (.NET Framework)" vs "... (.NET Standard)" option.
Related
My ultimate objective is to build a class library (Calculator.dll) in C#, containing functions that will be made accessible to Excel via VBA.
I had hoped to avoid the need to register the dll, and rather, use the Declare Function statement in the VBA code, but apparently this is not possible and my research has pointed me to needing to make the class library COM-Visible, then register it, and add it as a reference to the VBA project. It seems like this was a matter of clicking a box in a dialog for the project properties in earlier Visual Studio versions, but I don't see the box in VS2022?!
These are the steps I've taken with a "toy" example, and the problems I've encountered.
(1) I built the following .dll with a class Calculate and a simple method to Add two integers. Since we use 32-bit Excel, I configured it to x86.
namespace ClassLibraryCalculator
{
public class Calculate
{
public int Add(int a,int b){ return a + b; }
}
}
(2) From the command prompt, running as administrator, I attempted to run
regsvr32 "ClassLibraryCalculator.dll" but encountered an error "..was loaded but the entry-point DllRegisterServer was not found"
From searching around, the remedy for this is said to be to modify the project properties, the was (in earlier versions of VS?) a dialog box
with a check box, but I see nothing related to COM in Visual Studio 2022 Project Properties.
First make sure you create a project of type "Class library (.NET Framework)" that uses the classic Windows .net Framework like version 4.8. Do not choose the "Class library" project type that is based on .NET Standard and supports multiple different operating systems.
After creating the project, open the project properties by right-clicking on the project in the Solution Explorer and selecting "Properties".
In the project properties, go to "Application", then click on "Assembly Information".
In the "Assenmbly Information" dialog, enable the "Make assembly COM-Visible" checkbox.
For details see Turn a simple C# DLL into a COM interop component
Note that you can use the setting "Register for COM interop" on the "Build" area of the project properties to register the DLL (VS needs to run with admin privileges for that). When trying to register from command line, don't use "regsvr32", but "regasm". Be aware that there is a 32bit and a 64bit version of regasm available. Use the correct one.
Further important hints:
If you run Office as 64bit executables, choose "Platform target = x64" in the Build area in the project properties.
If you run Office as 32bit executables, choose "Platform target = x86" in the Build area in the project properties.
Note that "Any CPU" will not work. If you want to support both 32bit and 64bit instances of Office, you need to build two variants of your dll and register both.
This is the sample class I use for testing:
using System;
using System.Runtime.InteropServices;
namespace ClassLibrary4
{
[Guid("ECB682F0-8AF1-40EA-B73A-1FACF3C7F742")]
public interface IClass1
{
void Test();
}
[Guid("4EC93EC5-FA8C-4E82-8931-E47D979BDA93")]
public class Class1 : IClass1
{
public void Test()
{
System.Console.Beep();
}
}
}
Note that you cannot use these GUIDs but must use your own ones. Use the "Tools > Create GUID" command in Visual Studio for that.
Here is how I use the class from VBA after activating the reference:
' Declare variable with interface type
Dim c As ClassLibrary4.IClass1
' Create from class type
Set c = New ClassLibrary4.Class1
' Use.
c.Test
I followed a ton of SO guides in order to install Ghostscript in my MVC C# app but I cannot make the code below be recognized. It keeps saying "GhostscriptRasterizer could not be found (are you missing a using directive or an assembly reference?)"
public ActionResult PDFToImages(string pdfFilePath)
{
//...
using (var rasterizer = new GhostscriptRasterizer())
{
//...
}
//...
}
I am using Visual Studio and here's what I've already tried:
Get the .exe file from https://www.ghostscript.com/download.html and installed it. Then manually include gsdll32.dll in my project as "content" (menu: Add existing item);
On Visual Studio went to "Tools>NuGet Package Manager>Manage NuGet Packages for solution" and then installed Ghostscript.NET by Josip Habjan.
Also on NuGet Package Manager tried to install Ghostscript dlls by Matthieu - Get an error "Failed to add reference to 'gsdll32'. Please make sure that the file is accessible, and that it is a valid assembly or COM component."
On Package Manager Console did "Install-Package Ghostscript -Version 9.2.0" and got also the error above
If your objective is to make uso of Ghostscript .NET directly, you would not need to reference the original Ghostscript DLL from your project (as I said, until you desire to do so).
I tested Ghostscript .NET over Windows 7 and windows 10, with Visual Studio Community 2017 simply following these steps:
Install Ghostscript 9.52 for Windows (32 bits).
Using Nuget package manager, added Ghostscript .NET to my solution.
Include using code lines, as required (main namespace and Rasterizer for your case should work, I use Processor, in addition):
using Ghostscript.NET;
using Ghostscript.NET.Processor;
using Ghostscript.NET.Rasterizer;
I have checked in a new Console Application project the using clause (which makes use of Rasterizer class) that you have provided, and does not return any error, if I perform these steps previously.
Please, try again repeating the actions mentioned, and let me know if you manage to use Ghostscript that way.
I am trying to upgrade a bunch of old c# projects to consume nuget packages that I have made from old assembly dependencies. I want to write a C# program to update all the csproj files to reference the package.
I have the code using nuget.core making a dictionary of dependent assemblies to a nuget package. I can iterate over the references in my project file and find the needed nuget package from my repository.
var localRepo = PackageRepositoryFactory.Default.CreateRepository(nugetCachePath);
var packages = localRepo.GetPackages();
foreach (var package in packages)
{
foreach (var assemblyReference in package.AssemblyReferences)
{
assemblyToPackage.Add(Path.GetFileNameWithoutExtension(assemblyReference.Name).ToLower(),package);
}
}
I think I need to use Nuget.Core ProjectManager to add the reference to my project file (csproj).
<ItemGroup>
<PackageReference Incluse="KB.MyOldAssemblyPackage">
<Version>1.0.0</Version>
</PackageReference>
</ItemGroup>
What I can't figure out is how to get an instance of ProjectManager or any examples on how to use it to add the nuget reference. I know I could simply inject the xml with an xdocument but since I made the effort to use nuget.core I was hoping to find a solution using it.
Any help out there?
I don't understand what ways to manage packages you use now, but if it's packages.config, then I think better migrate to PackageReference. For it's may use NuGet PackageReference Upgrader that convert your dependencies from packages.config to PackageReference format.
After that you can add/remove our packages with NuGet Package Manager UI extension that built-in in Visual Studio 2017.
UPD2. Visual Studio 17 Preview 3 has tool for migrate from packages.config to PackageReference.
Also MSBuild 15.1 + has built-in NuGet targets such as restore and pack that you can combining with custom build targets. It's make easier build process.
If you still want to write program to added references to .csproj you can create extension for Visual Studio.
UPD1. Get IEnumerable<Project> from GlobalProjectCollection and parse libraries names from the Include attributes:
GetReferences -
public static IEnumerable<string> GetReferences(IEnumerable<Project> project)
{
return project.Select(p => p.GetItems("Reference").Select(i => i.EvaluatedInclude);
}
After that check availability this library in your NuGet repository with help your code and if exists, then remove current reference and create new:
CreateReference-
using Microsoft.Build.Evaluation;
using System.Collections.Generic;
namespace NuGetReference
{
public static class Reference
{
public static void CreateReference(string projectName, string packageName, string packageVersion)
{
Project project = ProjectCollection.GlobalProjectCollection.LoadProject(projectName);
project.AddItemFast("PackageReference", packageName, new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("Version", packageVersion) });
project.Save();
}
}
}
Migrate from packages.config to PackageReference | Project Class | GlobalProjectCollection | AddItemFast
Short answer.
You can't.
The NuGet.Core dll is NuGet 2.x, while PackageReference was introduced in 4.x
4.x has a more modular approach, and there isn't one package you can use to achieve your goal.
If you have Visual Studio 2017, you can use the latest 15.7 release (to be released in 2 weeks or just use the preview) to migrate your packages to PackageReference.
That's a built in tool that should handle most of your scenarios if compatible.
If you're really stuck with having to this programmatically the following code should be a great start.
My question is similar to this one, although it doesn't really address my issue.
I am working on some new AWS Lambda functions, and I would like to keep their implementation in separate class libraries for reuse. I'm testing this concept using two solutions:
A solution with a single .NET Standard class library project. This class library has a reference to HTML Agility Pack.
A solution with a single .NET Core 2.0 console application project.
Class library:
using System;
using HtmlAgilityPack;
namespace ClassLibrary1
{
public class Class1
{
public static bool FoundDotNet(string html)
{
bool foundDotNet = false;
HtmlDocument document = new HtmlDocument();
document.LoadHtml(html);
var titleNode = document.DocumentNode.SelectSingleNode("//title");
if (titleNode != null)
{
string titleText = titleNode.InnerText;
if (titleText.ToLower().Contains(".net"))
{
foundDotNet = true;
}
}
return foundDotNet;
}
}
}
Console application:
using System;
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
var foundDotNet = ClassLibrary1.Class1.FoundDotNet("<html><head><title>.NET WTF Buddy</title></head><body>You're doin' me a confuse.</body></html>");
Console.WriteLine(foundDotNet);
}
}
}
Both projects build without issue. However, the HTML Agility Pack assembly isn't copied into the Debug directory for either of the projects, and when I try to run the console application, I get Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'HtmlAgilityPack'
I have the package management format set to "PackageReference" for both projects, which I thought would handle the transitive dependency correctly. HTML Agility Pack is listed in the json.deps file, so I'm not sure what the problem is.
"HtmlAgilityPack/1.7.1": {
"dependencies": {
"System.Net.Http": "4.3.2",
"System.Xml.XPath": "4.3.0",
"System.Xml.XPath.XmlDocument": "4.3.0",
"System.Xml.XmlDocument": "4.3.0"
}
If I move the the class library project into the same solution as the console application, it works fine. What's preventing me from separating my code into separate solutions?
I'm using a large, complicated library in several solutions and the library has many transitive dependencies.
First, set up your library. Right click on the library's project name and choose Properties. About halfway down you'll see a tab labeled Packages. You can use that to auto-generate the NuGet package every time you rebuild the project. Just increment the version number. I use four position version numbering -- the first three are semver-style (major release, minor release, patch release), and the fourth one I increment manually for each new build.
I recommend creating a folder on your drive or network specifically for your local NuGet packages. You can create folders under that for each project. Then you point your debug and release build output to that project folder, and the NuGet package will be generated there, too.
Finally, back in Visual Studio, go to Tools -> Options -> NuGet Package Manager -> Package Sources and add that top-level folder as a package source.
From there it's simple -- open your NuGet dependencies in your consuming app. There's a drop-down at the top right where you can choose the package source. It will automatically search all the child folders and find whatever packages you've created. Now when you tweak your library, it's just a single click to update the client apps.
I've some problem when using .net standard in .net framework 4.6.2 consoleapps.
I could reduce the problem to this:
Given:
I create a .net standard 1.5 client library vis vs 2017 with this single class
public class Class1
{
public List<int> Get()
{
return new List<int>() { 1, 2, 3, 4, 5, 65, 6 };
}
}
Now I create a new .net 4.6.2 console application which is just calling the method of this class:
static void Main(string[] args)
{
var foo = new Class1();
Console.WriteLine("Done!");
Console.ReadLine();
}
Now I get
System.IO.FileNotFoundException: 'The File or Assembly
"System.Runtime, Version=4.1.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a was not found
When I add the .net standardlib nuget package to the .net fx console it works. but then the system.runtime would be aviable via GAC and via nuget reference which seems to be quite ugly for me.
I pushed this short test solution here: https://github.com/Gentlehag/NetStandardSample
What am I missing?
I've added a repo that shows you how to do this. From the README.md:
Requirements
Generally speaking, using libraries targeting .NET Standard in an application
targeting .NET Framework requires the application project to include a NuGet
reference for .NET Standard (NETStandard.Library). This ensures that the right
set of assemblies are included with the application.
In Visual Studio 2015, the default way of consuming NuGet packages from .NET
Framework projects is via packages.config. I don't recommend this path as
this means that all assemblies are directly injected into the application
project, which will significantly bloat your project file. Instead, I recommend
you use project.json. To do this, perform the following steps:
Uninstall all packages (if you're still using packages.config)
Delete the empty packages.config
Add project.json file with this content:
json
{
"dependencies": {
"NETStandard.Library": "1.6.0"
},
"runtimes": {
"win": {}
},
"frameworks": {
"net462": {}
}
}
Please note that you can generally depend on the latest version of the
NETStandard.Library package, but you need to make sure to keep the framework
moniker in sync with the version of .NET Framework your app is targeting, i.e.
when you're targeting .NET Framework 4.6.1, you need to make sure to use
net461 instead.
This feels clumsy
Yes it is. We're planning on addressing this in two ways:
We're replacing project.json with an MSBuild based solution in Visual
Studio 2017. You'll still need to add the reference to NETStandard.Library, but
you no longer have to mess with the way packages are being represented nor
having to manually keep targeting information in sync.
We're planning to update .NET Framework so that future version of it come with
built-in support for .NET Standard, in which case the reference will no longer
be needed.
I found that adding the NETStandard.Library did not work for me, but ensuring that binding redirects were generated on build did the trick. For that you should ensure that you have
<PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
somewhere in your project file. This should work for console or web apps. If you're having problems running unit tests, you can use this:
<PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
The GenerateBindingRedirectsOutputType is necessary as the unit tests are contained in a class library which doesn't have executable output by default, so this forces any redirect configuration to be written into the build artifacts, ready to be used when the tests are executing.
You can find more details of the issues involved here: https://github.com/dotnet/announcements/issues/31