I want to use a C++CLI (Managed C++) .dll to interface between Powershell v3 x86 and a (Unmanaged) C++ application.
I've tried to load a very simple "Hello World" program written in C++CLI using both Add-Type and [System.Reflection.Assembly]::LoadWithPartialName() in powershell but I get the error: "Could not load file or assembly"
I then wrote a C# wrapper for the C++CLI class, successfully loaded it into Powershell using the same method, but when I make a call that references the C++CLI code I get the same error. The C# code itself seems to not take any issue with calls to the C++CLI .dll, but Powershell does.
Accessor.h:
using namespace System;
namespace Accessor {
static public ref class Greeting
{
public:
static void HelloWorld();
};
}
Accessor.cpp:
#include "Accessor.h"
void Accessor::Greeting::HelloWorld()
{
Console::WriteLine("Hello World!\n");
}
Wrapper.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Accessor;
namespace AccessWrap
{
static public class Wrapper
{
static public void HelloWorld()
{
Greeting.HelloWorld();
}
}
}
What is the correct way to accomplish this? I've tried many other methods I've found online but none have worked for me.
Edit:
This is the exact error I get when trying to load the C++CLI .dll directly:
http://imgur.com/HF5VRkf
I was accidentally using 64 bit powershell, not x86 like I thought. I switched to x86 and it works fine.
Thanks for everyone's help.
Related
Has anyone ever run into an issue with .net 4.8 (c#) throwing "too long path" errors like below when run from a class library project. The same line of code is working fine for me if I run it from a windows forms project.
the error is below
"The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters"
The code I'm using to get the error is pretty simple. StrPath is a valid path that is say 350 chars long. ("c:\<350 Char path and filename>")
string a = Path.GetDirectoryName(strPath);
That's the simplest example, but it also happens when using any File or FileIO method like File and FileStream where I reference the long path.
Things I've tried
Most recommendations from https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN
setting the long path registry key
Including app manifest with settings to recognize long paths. (there were two different types of these I found on the net, neither worked)
prefixing with "\\?\"
Looked at what mscorlibs are being referenced by both the windows forms and the exe calling the class library dll. Both were identical and referenced 4.8 libs.
Both projects succeed when I use a shorter path than 260. So it is really a path len issue I think. It just seems to behave as if I'm using an older version of .net when run from the class library.
I call the class library from within a native C++ app (its a com interop). I can also get it to happen if I make a class library with that code into an nunit text fixture and call it from nunit-x86.exe. So the code would be as below for that. And fails when calling GetDirectoryName
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
using Omtool.Properties;
using System.Diagnostics;
using System.IO;
using OmXceedInterop;
using System.Windows.Forms;
namespace XceedTest
{
[TestFixture]
public class Class1
{
[Test]
public void Test()
{
string strPath = "C:\\Kit\\BlahServer\\Work\\CompoundFile\\Xceed\\2a0bb008-397b-476a-8e89-96caa7a11319\\HLCUVL1221104974\\THIS_NAME_IS_TOO_FRACKING_LONG_TO_BE_IN_ANY_WAY_USEFUL_YOU_SHOULD_BE_A_FRACKING_SHAMED_OF_YOURSELF_HLCUVL1221104974_Container Inspection_NANDA TILES,SL-DOCUMENTO CONTENEDOR-NEXP-220199-STYLE ACCESS-FLOOR DECOR-BAYTOWN TX-NO.1001367035.pdf";
int b = strPath.Length;
string a = Path.GetDirectoryName(strPath);
}
}
}
Again, the exact same lines of code work from the forms app but fail when called from the class library. There is something different about these two projects or perhaps the context under which they run that I'm just not understanding.
[EDIT]
It has to be the context. When I run my nunit class from the forms app, there is no path error. When I run that same assembly from nunit-x86.exe, I get the pathing error. It seems to depend on what's calling the class library as to whether I get the error or not
I'm trying to get this library to work inside my project. I've downloaded it to my documents folder and in the same documents folder I've created a new C# console app with just a Program.cs to try and run it. I can compile the library as far as I know.
Now, I've imported the project into my project using:
dotnet add C:/blabla/documents/tachograph-reader-test-code/tachograph-reader-test-code.csproj reference C:/blabla/documents/tachograph-reader/src/tachograph-reader-lib.csproj
and this worked just fine. As the following piece of code is added to my project file:
<ItemGroup>
<ProjectReference Include="..\tachograph-reader\src\tachograph-reader-lib.csproj" />
</ItemGroup>
Now for the life of me, I can't figure out how to use the library?
Intellisense does not see the library in any way. the using keyword doenst work either. De namespace should be DataFileReader but I cannot use it, and it won't compile.
By the way, I'm using VS CODE not vs studio.
So, how do I use such a library inside my project?
The problem is not in your project reference. I guess you have to add these three namespaces as follow:
using System.IO;
using System.Text;
using System.Xml;
Your Program.cs should look like:
using System;
using System.IO;
using System.Text;
using System.Xml;
using DataFileReader;
namespace tachograph-reader-test-code
{
class Program
{
static void Main(string[] args)
{
...
}
...
}
}
I want to output my C# project into a user defined folder.
Therefore I tried the following:
1. Setting the output path in the properties
Setting Output path in properties for all configs and any CPU
I built in Debug|x64 mode the C# project.
The solution contains a second project in C++ which has a config type of DLL. Goal is to use the DLL in C++ in my C# project.
C++ Project properties
Property Page for C++ Project
Here is the respective code for:
C# Project
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace ConsoleApp
{
class Program
{
[DllImport("NativeLibrary.dll")]
public static extern void HelloWorld();
static void Main(string[] args)
{
HelloWorld();
Console.ReadLine();
}
}
}
C++ Project
#include <iostream>
// Expose function
extern "C" __declspec(dllexport) void HelloWorld();
void HelloWorld()
{
std::cout << "Hello World" << std::endl;
}
The problem now is:
When I build both projects there are no errors.
When running the project, the C++ DLL cannot be found. This, I found out is because of the incorrect build pathes.
Whereas the C++ correctly resolves the environment variables I set, the C# project doesn't. It creates folders named as the variable name itself, instead of building into the resolved path name.
The build for the C++ file resolves correctly the output path
Output C++ build
The build for the C# project doesn't
Output C# build
I just cannot figure out how to resolve this issue, but I am also fairly new to this. Can you help me out?
Regards
Sebastian
I'm trying to import a VERY SIMPLE custom C# class into Python using pythonnet. I've never used C# or VS, so It's probably some stupid mistake I'm doing.
I have got a solid C# code base (not written by me) that I want to drive using Python.
I have this C# class:
using System;
public class MyClass
{
string text;
public MyClass(string text)
{
this.text = text;
}
public void Write()
{
Console.WriteLine(text);
}
}
In VS 2017, I've created a .NET Core Class Library project. It compiles fine and creates a MyClass.dll file.
Then I'm trying to import it in Python:
import sys
sys.path.append(r"C:\Users\myuser\source\repos\hello\MyClass\bin\Debug\netcoreapp2.1")
import clr
clr.FindAssembly(r"MyClass")
clr.AddReference('MyClass')
import MyClass
But I always get a "ModuleNotFoundError: No module named 'MyClass'" error.
Turns out I was compiling the DLL with .NET Core. Changing to .NET Framekwork 4.5 solved the problem.
I wish the error messages were more helpful.
I may be reposting but I cannot find solution of this.
I create a C# Comvisible Class. This is the following class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace COMTrial
{
[Guid("2B71BC1B-16F5-4A0D-A015-CAE658A10B07")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMyExample
{
string GetData();
}
[ClassInterface(ClassInterfaceType.AutoDual), ComSourceInterfaces(typeof(IMyExample))]
[Guid("2B71BC1B-16F5-4A0D-A015-CAE658A01B07")]
[ComVisible(true)]
public class Class1
{
public Class1()
{
}
[ComVisible(true)]
public string GetData()
{
return "Vikas";
}
}
}
Then I checked Register for Interop option and even made the complete assembly visible and compile the project and solution.
Then I went to excel and wrote this code:
Dim a as Object
set a = CreateObject("COMTrial.Class1")
It says,
ActiveX cannot create an object.
The only reason I think of is that I am running Office 2010 64 bit with Windows 7 64 bit.
Then I checked Register for Interop option
That will only register your assembly for 32-bit processes. Since this is the 64-bit version of Office, you will need to run Regasm.exe by hand. Do so from the Visual Studio Command Prompt, started with "Run as administrator". Be sure to use the 64-bit version of Regasm.exe, for .NET 4 it is located by default in C:\Windows\Microsoft.NET\Framework64\v4.0.30319. Note the 64. Use the /tlb and /codebase options to match the IDE's behavior.
Another improvement is to use the [ProgId] attribute explicitly so you don't have to guess at the name and won't have a problem if the project name is not "COMTrial".