How to use CppSharp - c#

I want to use CppSharp to create a C# wrapper for some classes from a C++ library which I intend to use from C# (on a 64 Bit Windows 10 system).
Unfortunately I am absolutely uncertain how to proceed. I cloned CppSharp into my filesystem and built it as described in the 'Getting started' section
https://github.com/mono/CppSharp/blob/main/docs/GettingStarted.md
I also ran all the test successfully.
From what I read in the documentation I was under the impression that to use CppSharp one has to create a C# application (for simplicity a console application), implement an abstract class from CppSharp and execute some commands from CppSharp. From
https://github.com/mono/CppSharp/issues/82
EDIT: Now I use the following code
using CppSharp;
using CppSharp.AST;
using CppSharp.Generators;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CppSharpTransformer
{
class DllDemoGenerator : ILibrary
{
public static void Main(string[] args)
{
ConsoleDriver.Run(new DllDemoGenerator());
}
void Setup(Driver driver)
{
var options = driver.Options;
options.GeneratorKind = GeneratorKind.CSharp;
var module = options.AddModule("Sample");
module.IncludeDirs.Add(#"C:\Users\Boehm.J\Documents\CppSharpSamples\Sample\include");
module.Headers.Add("Sample.h");
module.LibraryDirs.Add(#"C:\Users\Boehm.J\Documents\CppSharpSamples\Sample\lib");
module.Libraries.Add("Sample.lib");
}
public void SetupPasses(Driver driver) { }
public void Preprocess(Driver driver, ASTContext ctx)
{
}
public void Postprocess(Driver driver, ASTContext ctx)
{
}
void ILibrary.Setup(Driver driver)
{
}
}
}
which is in Program.cs of my Console application I called CppSharpTransformer.
I could make it compile ok (Visual Studio 2022, Console Project with NET 6.0) by adding the following DLLs to my project:
CppSharp.AST.dll
CppSharp.CLI.dll
CppSharp.CppParser.dll
CppSharp.dll
CppSharp.Generator.dll
CppSharp.Parser.Bootstrap.dll
CppSharp.Parser.CLI.dll
CppSharp.Parser.CSharp.dll
CppSharp.Parser.dll
CppSharp.Parser.Gen.dll
CppSharp.Runtime.dll
I added them under "Dependencies (Abhängigkeiten) > Assemblys" and also as files as members of my project.
But I can not execute the application currently, as I get the runtime error:
Could not load file or assembly 'CppSharp.Parser.CLI, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null'. Das System kann die angegebene
Datei nicht finden.
(The german text says "The system can not find the specified file").
But the dll of this name is, it seems, in place. It occurs in
C:\Users\Boehm.J\Documents\work\CppSharpTransformer\CppSharpTransformer
and in
C:\Users\Boehm.J\Documents\work\CppSharpTransformer\CppSharpTransformer\bin\x64\Release\net6.0

I've just run into the same issue.
Make sure you copy the Ijwhost.dll into your application's output path.
For example like this:
<Target Name="CopyNative" AfterTargets="Build">
<Copy SourceFiles="..\CppSharp\bin\Release_x64\Ijwhost.dll" DestinationFolder="$(OutputPath)" />
</Target>

Related

How can I add a static 'Main' method suitable for an entry point?

I am getting an error on my code that says "Error CS5001
Program does not contain a static 'Main' method suitable for an entry point"
I am coding in C# using Microsoft Visual Studio and .NET. This is my code.
using System.IO;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using System;
class projectsummer
{
[CommandMethod("OpenDrawing", CommandFlags.Session)]
public static void OpenDrawing()
{
string strFileName = "C:\\DRAFT.dwg";
DocumentCollection acDocMgr = Application.DocumentManager;
if (File.Exists(strFileName))
{
acDocMgr.Open(strFileName, false);
}
else
{
acDocMgr.MdiActiveDocument.Editor.WriteMessage("File " + strFileName +
" does not exist.");
}
}
}
I am not sure how to go about this error. Thank you!
Looking at this post and your previous question, let's try and break down what's going on.
You created a new Console application in Visual Studio. You did not tick "Do not use top level statements". This gave you a Program.cs file that was essentially empty (there was no "Main" method visible).
You erased the Hello World code given to you, and went to make a static method - the code from your previous question.
Damien_The_Unbeliever commented that based on the error, you put your method inside a "top level statement" file, and to put your method inside a class.
You wrap your method (which is still inside Program.cs) in a class, and now suddenly you get a Can't Find Entry Point error.
User Ryan Pattillo posted a great explanation of the original issue - where your method was "by itself" in the Program.cs file. You should follow their advice, but you should also ensure that this class is in its own file.
You should end up with this:
Program.cs
// this is the entire contents of the file
using ConsoleApp1;
ProjectSummer.OpenDrawing();
ProjectSummer.cs
using System.IO;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using System;
namespace ConsoleApp1
{
public class ProjectSummer
{
[CommandMethod("OpenDrawing", CommandFlags.Session)]
public static void OpenDrawing()
{
// ...
}
}
}
Change ConsoleApp1 to the name of your project.
The entry point of your application, which right now is the only file that has "top level statements", remains Program.cs, thus you fix the Can't Find Entry Point error.
Another adjustment you can make, which seeing you're new to C# might be useful, is to not use top level statements at all. Modify your Program.cs to this:
namespace ConsoleApp1
{
internal static class Program
{
// this is your program's entry point
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
ProjectSummer.OpenDrawing();
}
}
}
Change ConsoleApp1 to the name of your project.
You cannot use the AutoCAD .NET API out of process. To be able to use the AutoCAD .NET libraries, you have to build a "class library" project (DLL) and NETLOAD this DLL from a running AutoCAD process. See this topic about in-process vs out-of-process and you can start from this other one to see how to create an AutoCAD .NET project.

.net C# jdbc driver connector exception

I'm trying to connect to a hyperSQL database (HSQLDB) on my local machine from a c# application in visual studio.
I've ran through the steps to create the .net JDBC driver to build the dll, and also downloading the demo console application in the "download" section from the following url: http://nikolaiklimov.de/query-java-HyperSQL-database-with-csharp/
The demo application works!! i can connect to the database and query its contents . Next I have converted the console app into a class library then call the class library to query the DB but this is where it falls over and I get initialization errors of System.TypeInitializationException. any idea why the project falls over after converting to a class library. (if i convert the class library straight back a console app it works again).
The code and connection string are:
namespace HyperSQL
{
public static class sqlconnector
{
readonly static string CONNECTION_STRING =
ConfigurationManager.ConnectionStrings["HyperSQL"].ConnectionString;
const string SQL = "SELECT * FROM meeting";
public static void getdata()
{
try
{
java.sql.DriverManager.registerDriver(new org.hsqldb.jdbcDriver());
using (java.sql.Connection conn = java.sql.DriverManager.getConnection(CONNECTION_STRING))
{
java.sql.PreparedStatement ps = conn.prepareStatement(SQL);
using (java.sql.ResultSet rs = ps.executeQuery())
{
while (rs.next())
{
Console.WriteLine($"MEETING_NO={rs.getInt("MEETING_NO")}");
Console.WriteLine("------------------");
}
}
}
}
catch (Exception ex)
{
}
Console.ReadLine();
}
}
}
jdbc:hsqldb:hsql://localhost:3458/elitedb;crypt_key=DADADADADAADDADAD;crypt_type=AES;shutdown=true;write_delay=false;user=****;password=****
Ive added a console app to my solution after the conversion to a class libary. The console app code is below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
try
{
HyperSQL.sqlconnector.getdata();
}
catch (Exception ex)
{
}
}
}
}
Here is a link to download my solution created in visual studio. It contains a console application that calls a function in a class library. The class library (HyperSQL) itself is simply converted from a console application and can be converted back. You will need a running instance of HyperSQL on your machine to be able to connect successfully.
http://eliteservicedev.azurewebsites.net/DemoHyperSQL.zip
Have you seen the error listed in the original site you posted?
If your forget to add runtime dependencies to the build folder of your
project then you can get these errors: Could not load file or
assembly 'IKVM.OpenJDK.Util, Version=8.1.5717.0, Culture=neutral,
PublicKeyToken=13235d27fcbfff58' or one of its dependencies. The
system cannot find the file specified. TypeInitializationException:
The type initializer for 'org.hsqldb.jdbc.JDBCDriver' threw an
exception: FileNotFoundException: Could not load file or assembly
'IKVM.Runtime, Version=8.1.5717.0, Culture=neutral,
PublicKeyToken=13235d27fcbfff58' or one of its dependencies. 'The
type initializer for 'sun.util.locale.provider.LocaleProviderAdapter'
threw an exception.' FileNotFoundException: Could not load file or
assembly 'IKVM.OpenJDK.Text, Version=8.1.5717.0, Culture=neutral,
PublicKeyToken=13235d27fcbfff58' or one of its dependencies. 'The
type initializer for 'org.hsqldb.HsqlDateTime' threw an exception.'
InvalidCastException: Unable to cast object of type
'java.util.PropertyResourceBundle' to type
'sun.util.resources.OpenListResourceBundle'.
***** UPDATE
With the source project i see an error, looking in the bin\debug folder i see that non all the referenced file are copied to ConsoleApp1.exe bin folder: this is the compare result:
Confronto in corso dei file consoleapp1.txt e DEMOCSHARPTHYPERSQL.TXT
***** consoleapp1.txt
ConsoleApp1.exe
ConsoleApp1.exe.config
ConsoleApp1.pdb
hsqldb.dll
HyperSQL.dll
***** DEMOCSHARPTHYPERSQL.TXT
hsqldb.dll
HyperSQL.dll
*****
***** consoleapp1.txt
IKVM.OpenJDK.Jdbc.dll
IKVM.OpenJDK.Text.dll
***** DEMOCSHARPTHYPERSQL.TXT
IKVM.OpenJDK.Jdbc.dll
IKVM.OpenJDK.Localedata.dll --> Missing in ConsoleApp1.exe folder
IKVM.OpenJDK.Text.dll
*****
If i manually copy the missing dll on ConsoleApp1.exe folder the program run correctly. I think that is a visual studio bug
Seems VS is not copying all IKVM DLLs to output folder due to not resolving they are needed. Please see this SourceForge issue and this GitHub issue, the later one with my comments.

Determine if library loaded into Console, Desktop, or UWP app

I have a libary which needs to behave differently for console applications, desktop application (e.g. WPF), and for UWP apps.
How can I determine at run-time into which application type my libary is loaded?
Determining if it is a console application seems easy: How to tell if there is a console
For UWP, I can probably determine if WinRT is loaded. But how?
What distinguishing attributes do desktop applications have?
I ended up defining following enum:
public enum ExecutionMode
{
Console,
Desktop,
UniversalWindowsPlatform
}
which is passed to the constructor of the main class of my libary. Not a new idea, but very reliable (if used correctly).
Create a CustomAttribute in an assembly that is available to all of the applications like so
using System;
namespace MyNamespace.Reflection {
[System.AttributeUsage(AttributeTargets.Assembly)]
public class ApplicationTypeAttribute : Attribute {
public enum ApplicationTypes {
Console,
Desktop,
UWP,
ClassLibrary
}
public ApplicationTypeAttribute(ApplicationTypes appType) {
ApplicationType = appType;
}
public ApplicationTypes ApplicationType { get; private set; } = ApplicationTypes.Console;
}
}
Then add this attribute to your AssemblyInfo.cs file for a console application
using MyNamespace.Reflection;
[assembly: ApplicationType(ApplicationTypeAttribute.ApplicationTypes.Console)]
or a Desktop application
[assembly: ApplicationType(ApplicationTypeAttribute.ApplicationTypes.Desktop)]
etc.
Then wherever you want to check the calling type of the application that was started, use this
using MyNamespace.Reflection;
var assy = System.Relection.Assembly.GetEntryAssembly();
var typeAttribute = assy.GetCustomAttribute(typeof(ApplicationTypeAttribute));
if (typeAttribute != null) {
var appType = ((ApplicationTypeAttribute)typeAttribute).ApplicationType;
}
There is one caveat to this method. .NET Core apps have a different project structure and the AssemblyInfo.cs file is auto-generated at build time by default. You can override this behavior by specifying the following in the .csproj file in the Project node.
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
To match the old project file structure, you can create a Properties directory in the project directtory and then you can add an AssemblyInfo.cs file to that directory. Otherwise you can place the Custom Attribute definition in any file (after the usings and before the namespace declaration).

Integrating Prolog with C#

I am new to Prolog and C#. When I try to integrate Prolog with C# I found some errors,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SbsSW.SwiPlCs;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
// Environment.SetEnvironmentVariable("SWI_HOME_DIR", #"the_PATH_to_boot32.prc"); // or boot64.prc
if (!PlEngine.IsInitialized)
{
String[] param = { "-q" }; // suppressing informational and banner messages
PlEngine.Initialize(param);
PlQuery.PlCall("assert(father(martin, inka))");
PlQuery.PlCall("assert(father(uwe, gloria))");
PlQuery.PlCall("assert(father(uwe, melanie))");
PlQuery.PlCall("assert(father(uwe, ayala))");
using (var q = new PlQuery("father(P, C), atomic_list_concat([P,' is_father_of ',C], L)"))
{
foreach (PlQueryVariables v in q.SolutionVariables)
Console.WriteLine(v["L"].ToString());
Console.WriteLine("all children from uwe:");
q.Variables["P"].Unify("uwe");
foreach (PlQueryVariables v in q.SolutionVariables)
Console.WriteLine(v["C"].ToString());
}
PlEngine.PlCleanup();
Console.WriteLine("finished!");
}
}
}
}
It is not running, Before run this I was add reference SwiPlCs.dll. But it shows error "FileNotFoundException was unhandled, The specified module could not be found. (Exception from HRESULT: 0x8007007E)".
So can anyone help me to fix this error?
I got this coding here
The link you've provided has full explanation of this error:
If libswipl.dll or one of its dependencies could not found you will recive an error like
System.IO.FileNotFoundException: Das angegebene Modul wurde nicht gefunden. (Ausnahme von HRESULT: 0x8007007E)
An other common error is:
SWI-Prolog: [FATAL ERROR:
Could not find system resources]`
Failed to release stacks
To fix this add the SWI_HOME_DIR environment variable as described in SWI-Prolog FAQ FindResources with a statment like this befor calling PlEngine.Initialize.
Environment.SetEnvironmentVariable("SWI_HOME_DIR", #"the_PATH_to_boot32.prc");
This code is commented by default, Uncomment it and provide the correct path to the the_PATH_to_boot32.prc. As described in FAQ:
Solution
On Windows, it suffices to leave libswipl.dll in the installation tree (i.e., do not copy it elsewhere) and add the bin directory of the installation tree to %PATH%.
A cross-platform and robust solution is to use putenv() to put an appropriate path into the environment before calling PL_initialise().
...;
putenv("SWI_HOME_DIR=C:\\Program Files\\swipl");
if ( PL_initialise(argc, argv) )
PL_halt(1);
...
In the final version of your application you link the saved-state to the executable (using swipl-ld or cat (Unix)) and comment the putenv() call.

Creating a wrapper for a C# library in Python

Main goal: Create a wrapper for a C# library, which can be used in Python (2.6).
UPDATE: Now, I have updates to the method I am using, which is however not working well.
The code for the simple C# class library:
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace Test
{
[Guid("8F38030D-52FA-4816-B587-A925FDD33302")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface _TestClass
{
[DispId(1)]
string Eureka();
}
[Guid("BC3F6BB3-42C4-4F30-869A-92EA45BF68D2")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Test.TestClass")]
public class TestClass : _TestClass
{
public TestClass()
{
}
public string Eureka()
{
return "Hudson, we no longer have a problem!";
}
}
}
enter code here
In addition to this, I went into Project Properties and enabled the setting: Register for COM interop.
Also, in order to make the class library available to COM, I ticked Signing -> Sign the Assembly, and gave it a strong key.
Furthermore, whenever I compile, I unregister the old version with:
regasm -u Test /tlb:Test
And I register it with:
regasm Test.dll /tlb:Test
My problem is then, in the Python environment, I have the following main.py, which is not working:
import win32com.client
o = win32com.client.Dispatch("Test.TestClass")
The error is unforgiven.
thank you in advance!
A alternative would be if you you use Python for .NET. There seem to be alpha releases for Windows CPython 2.6 and 2.7 available. You could run simply:
import clr
clr.AddReference("Your.Assembly.Name")
import Test
test = Test.TestClass()
print test.Eureka()

Categories