MissingMethodException when trying to use PInvoke in SmartDevice project - c#

I have compiled a native dll for windows mobile SDK, and then created c# project to call it from. However, all i get is a MissigMethodException.
Dll is in the same folder as Managed executable file.
Here is how exported functions look in header:
namespace cuttingStream
{
/**
* Открывается файл и производится его проверка.
**/
__declspec(dllexport) bool open_png_file(char* , pngDataStructures* );
__declspec(dllexport) void close_png_file(pngDataStructures*);
...
}
Here is how i import them:
static class CuttingStreamWrapper
{
[DllImport("libpngStreamWrap.dll", EntryPoint = "open_png_file")]
public static extern bool OpenPngFile(string fileName, out pngDataStructures dataStruct);
[DllImport("libpngStreamWrap.dll", EntryPoint = "close_png_file")]
public static extern bool ClosePngFile(ref pngDataStructures dataStruct);
}
Here is dumpbin's output (relevant part):
1 0 00001340 ?close_png_file#cuttingStream##YAXPAUpngDataStructures###Z
2 1 00001194 ?open_png_file#cuttingStream##YA_NPADPAUpngDataStructures###Z
After marking functions with extern "C" in both source file and header, dumpbin output changed to:
ordinal hint RVA name
1 0 00001314 close_png_file
2 1 0000118C open_png_file
Which seems to be not mangled.
However, the problem remains. Here is the exception i recieve:
System.MissingMethodException was unhandled
Message="Не удается найти PInvoke DLL \"libpngStreamWrap.dll\"."
StackTrace only has the main function of a program, where i try to call wrapped function.
Update:
After running dependency walker on the dll i am trying to load, i've got 2 dependencies: Coredll.dll, msvcr90d.dll. On the device i am trying to deploy to ther is only msvcr80.dll. That explains the failure to load.

The issue was rooted in the dll's dependency on msvcr90d.dll, that is not found on the device. Once dependency was eliminated (by switching to /MTd from /MDd), dll was found.

Related

How to create a C++ or C++/CLI wrapper for a static lib to use in C#

I only have a lib file and its header file (static library?) I want to use this in C#. From googling I have come to the conclusion I need to write a wrapper dll that C# will be able to use.
I have tried writing this both in C++ and C++/CLI but when I run my program I get a error stating that
Unable to load DLL 'foo.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
I have already used a dependency checker and my dependencies are fine so I'm assuming my dll setup is incorrect.
I am only trying to use functions from the lib not classes.
Here is an example of my cs file
using System;
using System.Runtime.InteropServices;
using System.Text;
public class FooWrapper
{
[DllImport("FooWrapper.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern short DoSomething(ushort var);
}
// More functions like the one above
I have added FooWrapper.dll to my project by going into VS and doing Solution Explorer > Add > Existing Item > Directory that my dll is in > FooWrapper.dll
For my DLL I just created a new DLL C++ project, added a class named FooWrapper. This resulted in having a project that has
Project
|
-Refrences
|
-External Dependencies
|
-Header Files
-- FooWrapper.h
-- framework.h
-- pch.h
|
-Resource Files
|
- Source Files
--FooWrapper.cpp
--dllmain.cpp
--pch.cpp
FooWrapper.h looks something like this
#pragma once
#ifndef FOOWRAPPER_H
#define FOOWRAPPER_H
#include <string>
#include "Foolib.h" // header file that comes with lib file i originally had
using namespace std;
#ifdef __cplusplus
extern "C" {
#endif
#ifdef FOOWRAPPER_EXPORTS
#define FOOWRAPPER_API __declspec(dllexport)
#else
#define FOOWRAPPER_API __declspec(dllimport)
#endif
FOOWRAPPER_API I16 DoSomething(const I16 var) // I16 is defined (typedef) as a short
#ifdef __cplusplus
}
#endif
#endif
I have also linked the lib and header by adding the include directory under Properties>C/C++> Additional Include Directories
and Linker > Additional Library Directories > *Directory that FooLib.lib is in *
and Linker > Input > Additional Dependencies > *Directory that FooLib.lib is in * > FooLib.lib
So lastly when I call DoSomething the code stops and gives me the Exception from HRESULT: 0x8007007E error message.
Can someone maybe tell me if I skipped a step? Or am I supposed to use C++/CLI to create the library? If so I can try that again. Or is this not possible without seeing the implementation of the FooLib.lib code?
castro's comment solved the issue:
Try creating your C++ project as a CLR project. So long as you follow the rules (only include native code in the cpp) it should then be as simple as adding your project as a reference to your C# project. Going from memory so I can't say for sure, but this might help you get started: learn.microsoft.com/en-us/cpp/dotnet/…

DllImport for Dotnet core returning DLLNotFoundException for present DLL

Over the past few days I have been trying to interface with a C library (built for an ARM platform) on linux, in dotnet core. All I am trying to do is call a simple function which (essentially) returns a string.
However, I have no experience of using DLLImport or interop on the whole in C# and I am struggling.
The C code looks like (with substitute names as I am using a work platform):
int version(int argc, char *argv[])
{
return READ_DATA(0,
version, //callbackfunction
"version: 0x%04x\n"); //formatting string
}
public class Board
{
private Interop_Commands _commands = new Interop_Commands();
public string GetVersion()
{
return _commands.GetVersion();
}
}
internal class Interop_Commands
{
public const string LIBRARYPATH = "libname";
[DllImport(LIBRARYPATH,CharSet=CharSet.Unicode, CallingConvention =CallingConvention.Cdecl)]
public static extern int version(int argc, StringBuilder argv);
public string GetVersion()
{
var sb = new StringBuilder();
Console.WriteLine($"Calling {nameof(version)}");
version(0, sb);
Console.WriteLine($"Called {nameof(version)}, got: {sb.ToString()}");
return sb.ToString();
}
}
with the calling class (main for this very simple proof of concept/trial code):
static void Main(string[] args)
{
Console.WriteLine("Getting Version from board..");
var board = new Board();
Console.WriteLine(board.GetVersion());
Console.WriteLine("done");
Console.ReadLine();
}
The folder structure is (simplified):
folder
|--> Dll/runtime
|--> libname (note no .so here, just libname)
Any help would be appreciated, I am finding examples of C imports/usages limited, and also finding examples limited for how to use custom libraries in dotnet core.
EDIT 1:
Following help from #Sohaib Jundi, I have added the extern so the signature is now: (it wouldnt compile with extern "C")
extern int version(int argc, char *argv[])
I am unsure what to try next.
but dotnet core wont publish with x86 and target runtime set to linux-arm, just throws an unknown exception, with the log file not being very helpful..
If i use the compiled library with the previous code (AnyCPU + linux-arm), then the DllNotFoundException is still thrown
* EDIT 2: *
As it turns out, the original no extension file i was using appears to be an executable referencing a static library (which ends up compiled into the executable). rebuilding I have managed to get the static library separate, but still get the same DllNotFoundException. Does anyone know what the search procedure is for the DllImport on dotnet core?
The interop/import code now looks like:
[DllImport("libname",
CallingConvention =CallingConvention.Cdecl,
EntryPoint= "version")]
public static extern int version(ref uint val);
where the static lib code looks like:
extern int version(uint32_t *);
After some playing around, I managed to get an example to work.
Follow these steps:
1. export your function from the dll, i.e: add extern "C" __declspec(dllexport) to the function signature
2. Make sure that both the dll and your dotnet core application have the same architecture. don't keep the dotnet core as "Any CPU", force it to the same architecture as the dll. (project properties -> build -> platform target = x86 or x64)
I have found the solution.. the library was being compiled as a .la (statically linked library) rather than a .so (shared object) library. The DllImport doesnt work with statically linked libraries so.. a recompilation of the library into a shared object library has meant it will now find the dll (I also exported LD_LIBRARY_PATH as pwd to make sure it was in the search path..).
Once this was in, the rest of the code fell into place. The matching dll import declaration for the version above was correct (from *EDIT 2 *) - using ref uint. So now I have to extend the methods supported in my interop class to fully support the library.
Thanks for your help #Sohaib Jundi

Dll become unable to load when calling function from another dll

Now I have a Unity (C#) project, which calls my C++ project from a dll. They both worked fine, so as calling C++ functions from Unity.
However, when I try add one line to call a function another library (NLOpt library, from another dll) in the C++ project, the generated dll becomes unable to be loaded in the Unity project.
Plugin.h
extern "C" __declspec(dllexport) bool __stdcall LoadData(int agent_num, int frame_num, float* data);
Plugin.cpp
#include "Plugin.h"
#include <nlopt.h>
__declspec(dllexport) bool __stdcall LoadData(int agent_num, int frame_num, float* d)
{
...
nlopt_opt opt = nlopt_create(NLOPT_LN_COBYLA, 3); //this line
}
As I add the line above, Unity will the following error:
Plugins: Failed to load 'Assets/Plugins/BirdOpti/BirdOpti.dll'
and
DllNotFoundException: Opti
I have tried couple of times so I am sure the problem is the line.
Did I do anything wrong?
Adding also the used dll file to the plugin directory solves the problem.

Exception when using DllImport on unmanaged DLL containing Thread-Local-Storage (TLS) callback

I have a .NET application that loads an unmanaged DLL (C++) containing several entry points.
The setup works fine and I can use information returned (i.e. strings) by the entry points in .NET.
But as soon as the linker includes logic that depends on threads (e.g. _beginthread) a .tls section is added to DLL, which can be
seen by running dumpbin /exports, then the program throws exceptions: Access violations and EntryPointNotFound exceptions.
As an example I have created two simple projects that demonstrates my case:
TestApi: C++ project that outputs a DLL
ConsoleApplication1: C#.NET project that loads TestApi.dll and invokes an exported DLL function
The above project doesn't include calls to _beginthread, but instead a Thread-Local-Storage (TLS) callback was added manually, which causes the run-time errors.
The example projects can be downloaded here: http://www.tempfiles.net/download/201404/343692/TestApi.html
The C# code of ConsoleApplication1:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
[DllImport("TestApi.dll", EntryPoint = "TestFunction", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.LPStr)]
private static extern string TestFunction();
static void Main(string[] args)
{
try
{
string dllString = TestFunction();
Console.WriteLine("String from DLL: " + dllString);
}
catch (System.Exception ex)
{
Console.WriteLine("Caught exception: " + ex);
}
}
}
}
The C++ code of TestApi.dll:
#pragma unmanaged
#include <string>
#include <objbase.h>
extern "C" __declspec(dllexport) char* TestFunction()
{
// Return string to managed side
std::string cppString = "This is a string from the unmanaged DLL";
size_t stringSize = strlen(cppString.c_str()) + sizeof(char);
char* returnString = (char*)::CoTaskMemAlloc(stringSize);
strcpy_s(returnString, stringSize, cppString.c_str());
return returnString;
}
The DLL contains 1 entry point as expected (dumpbin /exports TestApi.dll):
ordinal hint RVA name
1 0 00001010 TestFunction = _TestFunction
Summary
1000 .data
7000 .rdata
1000 .reloc
1000 .rsrc
3000 .text
The above .NET application works as expected, printing the following output:
String from DLL: This is a string from the unmanaged DLL
If I add the following snippet, which adds a TLS callback to the DLL, everything breaks:
#pragma comment(linker, "/INCLUDE:__tls_used")
#pragma comment(linker, "/INCLUDE:_tls_entry")
#pragma data_seg(".CRT$XLB" )
VOID NTAPI MyCallback(PVOID handle, DWORD reason, PVOID resv)
{
}
extern "C" PIMAGE_TLS_CALLBACK tls_entry = MyCallback;
The DLL now contains 1 entry point as expected, but also a .tls section at the end of "Summary":
ordinal hint RVA name
1 0 00001010 TestFunction = _TestFunction
Summary
1000 .data
7000 .rdata
1000 .reloc
1000 .rsrc
3000 .text
1000 .tls
The .NET application now outputs:
Unhandled Exception:
Unhandled Exception:
Segmentation fault
When running the application in Debug I get:
An unhandled exception of type 'System.AccessViolationException' occurred in ConsoleApplication1.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Dumpbin shows no indication that the DLL should be illformed whatsoever, but nevertheless I get the exceptions above.
When I run my original application the symptoms are the same:
If a .tls section is available from dumpbin the program crashes with
access violations
If no .tls section is available the program works fine
Do I miss something here? Is it possible that DllImport only handles DLLs containing no .tls section?
My obvious solution is to refactor the code so my entry points don't depend on thread logic, so the linker doesn't add the .tls section to the DLL.
But, I would still like to know why this is happening. Any thoughts?
The environment used:
Windows 7 Enterprise SP1
Visual Studio 2012
.NET Framework 4
It turns out that the /clr flags does something nasty with the PE format of the DLL. If the /clr flag is enabled I get the following output when loading the DLL from Python 2.7:
>>> import ctypes
>>> apidll = ctypes.cdll.LoadLibrary('TestApi.dll')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\ctypes\__init__.py", line 443, in LoadLibrary
return self._dlltype(name)
File "C:\Python27\lib\ctypes\__init__.py", line 365, in __init__
self._handle = _dlopen(self._name, mode)
WindowsError: [Error 193] %1 is not a valid Win32 application
Disabling the /clr flag gives me:
>>> import ctypes
>>> apidll = ctypes.cdll.LoadLibrary('TestApi.dll')
>>>
My solution (as #HansPassant also suggested in the comment above) was to disable the /clr flag and everything worked even though the DLL contained a .tls section.

Calling Unmanaged C++ from C#

I'm running VS2012 on Win7 with .NET 4.0.
I've tried the following:
Create C++ DLL project
Checked\Unchecked the export symbols box
I've made sure my platform targets are the same. In my case, win32
I've added the necessary extern "C" and __declspec(dllexport) where needed.
I've successfully compiled my DLL and have tried to reference it in a C# project.
Unfortunately, I get an error telling my it can't be added and that I need to make sure it's a valid assembly or COM object.
I've given up trying to get my code to export, so I'd be happy with just the example "42" getting through!
I've tried looking at it with dumpbin and it is correctly exporting symbols:
1 0 00011023 ??0CEvolutionSimulator##QAE#XZ
2 1 00011127 ??4CEvolutionSimulator##QAEAAV0#ABV0##Z
3 2 00011005 ?GetNumber#CEvolutionSimulator##QAEHXZ
4 3 0001104B ?fnEvolutionSimulator##YAHXZ
5 4 00017128 ?nEvolutionSimulator##3HA
My brain is fresh out of ideas. Can someone please enlighten me? I seem to get this error no matter what I try.
You need to pinvoke the functions residing in your C++ DLL (exported using extern "C") from your .NET code using the DllImportAttribute. You can't reference your C++ DLL like a .NET assembly, and you can't use classes from the DLL, only DllImported C-like functions.
Example from msdn:
using System;
using System.Runtime.InteropServices;
class Example
{
// Use DllImport to import the Win32 MessageBox function.
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);
static void Main()
{
// Call the MessageBox function using platform invoke.
MessageBox(new IntPtr(0), "Hello World!", "Hello Dialog", 0);
}
}

Categories

Resources