Is it possible to create a Portable class library with Roslyn? - c#

This is a very simple code that generates a dll that can be referenced from a Portable class library, but, it is prone error because when I add any reference it accepts non portable references.
How can I tell for sure that what I'm trying to generate is on the Portable profile?,
Here is the code:
using System.IO;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
namespace Ros1
{
class Program
{
static void Main(string[] args)
{
SyntaxTree tree = SyntaxTree.ParseText(
#"using System;
namespace HelloWorld
{
public class A
{
public int Sum(int a, int b)
{
return a + b;
}
}
}");
var co = new CompilationOptions(OutputKind.DynamicallyLinkedLibrary);
var compilation = Compilation.Create("HelloWorld", co)
.AddReferences(MetadataReference.CreateAssemblyReference("mscorlib"))
.AddSyntaxTrees(tree);
using (var file = new FileStream("Sum.dll", FileMode.Create))
{
compilation.Emit(file);
}
}
}
}

Yes. Portable Class Libraries (PCL) as a concept is transparent to the compiler. It's basically a project system and reference assemblies feature only. If you want to create a portable class library that targets, say .NET for Windows Store apps and .NET 4.5, you should compile against the assemblies in this folder:
%ProgramFiles(x86)%\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile7
Every profile folder has a subdirectory called SupportedFrameworks which indicates which frameworks it supports.
To make the PCL work great in Visual Studio, you should also include the TargetFrameworkAttribute. Make sure version and profile are set correctly. For the example above you would need
[assembly: TargetFramework(".NETPortable,Version=v4.5,Profile=Profile7",
FrameworkDisplayName=".NET Portable Subset")]
I don't think we ship these assemblies outside of Visual Studio, so you will need an installation of Visual Studio 2010 (with the PCL extension installed) or Visual Studio 2012.

I believe Paulo's asking whether it is possible to use Roslyn in a Silverlight/portable app. The answer is no, Roslyn currently only works in full trust on desktop CLR. It's certainly something we'd like to enable in future.

Related

Making C# Class Library COM-Visible in Visual Studio 2022

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

What is causing the 'WrongThreadException' in Unity 3D?

I want to integrate a C++ project in Unity. Unity provides a mechanism called I2CPP (Intermediate Language To C++) which allows to add C++ code to your unity project. I've created a simple C++ class and header in a "Blank App (Universal Windows C++/CX)" project in Visual Studio.
// header
namespace SomeNamespace {
public ref class MyRuntimeClass sealed
{
public:
// Constructor
MyRuntimeClass();
// Method to check if initialized
bool IsClassInitialized();
private:
bool _isRuntimeInitialized = false;
};
}
and
// implementation
using SomeNamespace;
MyRuntimeClass::MyRuntimeClass()
{
_isRuntimeInitialized = true;
}
bool MyRuntimeClass::IsClassInitialized()
{
return _isRuntimeInitialized;
};
I've made in Unity a simple project and made the necessary changes in the Player settings outlined in the documentation. I also added a cube as a game object and attached to the cube a script which uses my C++ code, i.e.
#if ENABLE_WINMD_SUPPORT
using SomeNamespace;
#endif
public class RuntimeSampleUnity : MonoBehaviour
{
#if ENABLE_WINMD_SUPPORT
private MyRuntimeClass _myRuntimeClass;
#endif
// Default MonoBehaviour method
void Start()
{
#if ENABLE_WINMD_SUPPORT
// New instance of runtime class
_myRuntimeClass = new MyRuntimeClass();
// Check to see if we initialized C++ runtime component
var isInit = _myRuntimeClass.IsClassInitialized();
Debug.LogFormat("MyRuntimeClass: {0}", isInit);
#endif
}
}
In a final step, I've added the winmd file from the C++ project to my assets in Unity. The project builds fine, but when I run the project I get an Platform.WrongThreadException: The application called an interface that was marshalled for a different thread. What is causing this exception (and how do I fix it)?
EDIT: To elaborate a bit why I'm doing what I'm doing: Microsoft provides a project which shows how to integrate OpenCV (C++) to HoloLens-based projects. While it provides a UWP project which mixes OpenCV and C#, it doesn't show how to integrate this particular project into Unity. Somebody actually made this possible via I2CPP. While I ran into issues using his Visual Studio 2017 based project into Visual Studio 2019, I've tried to make a minimal example to understand how it (basically) works.
I think you're misunderstanding the concept of IL2CPP.
IL2CPP (Intermediate Language To C++) is a Unity-developed scripting
backend which you can use as an alternative to Mono when building
projects for various platforms. When building a project using IL2CPP,
Unity converts IL code from scripts and assemblies to C++, before
creating a native binary file (.exe, apk, .xap, for example) for your
chosen platform. Some of the uses for IL2CPP include increasing the
performance, security, and platform compatibility of your Unity
projects.
To use C++ you have to write a Native Plugin.

EB GUIDE Studio extension doesn't work anymore after switching to version 6.8

I tried to migrate an extension from Guide 6.7.3 to 6.8. Compilation did work without any changes, but the DLL is not loaded anymore.
It looks like the DLL is not even loaded, breakpoint in main constructor is not hit and Visual Studio claims that there are no symbols available.
Same version works correctly in Guide 6.7.3.
Stripped down minimal version which shows the problem:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Xml;
using Elektrobit.Guide.Studio.Workbench.ViewModels;
using Elektrobit.Guide.Ui.ViewModels;
using Elektrobit.Guide.Utilities;
[Export(typeof(IMenuItemProvider))]
public class TestMenuProvider : IMenuItemProvider
{
public string MenuId => "test";
[ImportingConstructor]
public TestMenuProvider()
{
}
public IEnumerable<IMenuItemViewModel> CreateMenuItems(object context)
{
return null;
}
}
Constructor TestMenuProvider() is run on 6.7.3 but not 6.8.
The example code works fine for me.
However, I stumpled upon a similar issue, so this might help you:
As they switched from x86 to x64 with version 6.8, I could imagine you may have missed to update the build settings of your extension project.
In the project properties of the Visual Studio project, head for Build -> Platform target and make sure it is set to x64 for all build configurations.

.NET Core, .NET Standard and Transitive Dependencies across Solutions

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.

Console app in C# fails to execute as soon as data types in Autodesk libraries are used

I'm developing some AutoCAD add-ons in C# and I was hoping to work/debug my classes in a console application first until I'm ready to implement the functionality inside AutoCAD. /dot net libraries cannot be unloaded and one needs to restart/reload acad each time the code is modified/
Interestingly I'm finding that as soon as I declare a variable which uses an autocad data type my console app refuses to run and Im presented with a "the application is in break mode" screen in visual studio. For example this code does not run:
using System;
using Autodesk.AutoCAD.Geometry;
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hi");
Point2d p;
Console.ReadKey();
}
}
}
Trying this referencing Autodesk C3D 2016 dll libraries. Does anyone have an explanation of what is going on here and/or any workarounds?
thnks
The AutoCAD .NET API is designed to run in-process only.
AutoCAD .NET libraries can only be used to build plug-ins (DLL) which have to be loaded in AutoCAD for execution.
To debug your AutoCAD Add-On code, you need to create a C# Class Library Project referencing the Autodesk CAD 2016 Sdk Libraries, and encapsulate your code on public method that declared with CommandMethodAttribute. With this method declared with CommandMethod it's the be your trigger between the AutoCAD prompt command and your Add-On code.
public class AcadCommands
{
[CommandMethod("TriggerCmd")]
public void TriggerCommand
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage("Hi");
Point2d p;
}
}
Note: at your Visual Studio Project Properties, you need to configure to start debug pointed to acad.exe and when the AutoCAD applications starts, open some DWG and prompt the "NETLOAD" command to include your debbugable compiled DLL from your VS Project to AutoCAD Application context.

Categories

Resources