I have a rather baffling issue, a program that used to always work now only works once per reboot, when running it again I'm granted with:
Exception thrown: read access violation. this was 0xBF13D000.
I've extended a C++ project with C exports so I can use it from C#:
C exports:
KeyFinder::AudioData* new_audio_data(const unsigned frame_rate, const unsigned channels, const unsigned samples)
{
auto audio_data = new KeyFinder::AudioData();
audio_data->setFrameRate(frame_rate);
audio_data->setChannels(channels);
audio_data->addToSampleCount(samples);
return audio_data;
}
void audio_data_set_sample(KeyFinder::AudioData* audio_data, const unsigned index, const double value)
{
audio_data->setSample(index, value);
}
void keyfinder_progressive_chromagram(KeyFinder::KeyFinder* key_finder, KeyFinder::AudioData* audio_data, KeyFinder::Workspace* workspace)
{
key_finder->progressiveChromagram(*audio_data, *workspace);
}
KeyFinder::key_t keyfinder_key_of_chromagram(KeyFinder::KeyFinder* key_finder, KeyFinder::Workspace* workspace)
{
return key_finder->keyOfChromagram(*workspace);
}
enum key_t {
A_MAJOR = 0,
A_MINOR,
B_FLAT_MAJOR,
B_FLAT_MINOR,
B_MAJOR,
B_MINOR = 5,
C_MAJOR,
C_MINOR,
D_FLAT_MAJOR,
D_FLAT_MINOR,
D_MAJOR = 10,
D_MINOR,
E_FLAT_MAJOR,
E_FLAT_MINOR,
E_MAJOR,
E_MINOR = 15,
F_MAJOR,
F_MINOR,
G_FLAT_MAJOR,
G_FLAT_MINOR,
G_MAJOR = 20,
G_MINOR,
A_FLAT_MAJOR,
A_FLAT_MINOR,
SILENCE = 24
};
C# declarations:
[DllImport("libKeyFinder", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr new_audio_data(
uint frameRate, uint channels, uint samples);
[DllImport("libKeyFinder", CallingConvention = CallingConvention.Cdecl)]
private static extern void audio_data_set_sample(
IntPtr audioData, uint index, double value);
[DllImport("libKeyFinder", CallingConvention = CallingConvention.Cdecl)]
private static extern void keyfinder_progressive_chromagram(IntPtr keyFinder, IntPtr audioData, IntPtr workspace);
[DllImport("libKeyFinder", CallingConvention = CallingConvention.Cdecl)]
private static extern Key keyfinder_key_of_chromagram(IntPtr keyFinder, IntPtr workspace);
public enum Key
{
AMajor = 0,
AMinor,
BFlatMajor,
BFlatMinor,
BMajor,
BMinor = 5,
CMajor,
CMinor,
DFlatMajor,
DFlatMinor,
DMajor = 10,
DMinor,
EFlatMajor,
EFlatMinor,
EMajor,
EMinor = 15,
FMajor,
FMinor,
GFlatMajor,
GFlatMinor,
GMajor = 20,
GMinor,
AFlatMajor,
AFlatMinor,
Silence = 24
}
C# usage:
public void SetSample(uint index, double value)
{
audio_data_set_sample(_audioData, index, value);
}
What is really puzzling is that when I debug it, the seemingly disposed/destroyed pointer is already visible in the C# part: SetSample._audioData. Initially, when new_audio_data is called from C# I get a valid pointer like 0x032fe940 but for some reason it becomes 0xBF13D000. Note that it always become the value 0xBF13D000 so I've searched about such value online in a hope to spot a known memory pattern but without success.
As I said, there hasn't been any changes to the program, so I'm at a total loss as on what could be causing this.
Try add volatile for _audioData
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/volatile
It turned out that some of the native libraries needed to be all rebuilt using the same compiler version, now it works flawlessly !
Related
I'm trying to use XGBoost's dll (libxgboost.dll) to create a DMatrix (which is like a 2D array) and get how many columns it has. It runs fine until it throws a System.AccessViolationException at the int cols = ... line in the code below:
using System;
using System.Runtime.InteropServices;
namespace basicXgboost
{
class Program
{
[DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, IntPtr outputPtr);
[DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, IntPtr dmatrixColumnsPtr);
static void Main(string[] args)
{
IntPtr dmatrixPtr = Marshal.AllocHGlobal(1000000);
IntPtr dmatrixColumnsPtr = Marshal.AllocHGlobal(10);
int result = XGDMatrixCreateFromFile("../../libs/test.txt", 0, dmatrixPtr);
int cols = XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr);
Marshal.FreeHGlobal(dmatrixPtr);
Marshal.FreeHGlobal(dmatrixColumnsPtr);
}
}
}
Why does accessing unmanaged memory allocated with XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr) cause a System.AccessViolationException?
One possibility might be that I'm using pinvoke incorrectly for these functions. Below are the definitions for each dll function I use:
XGDMatrixCreateFromFile()
/*!
* \brief load a data matrix
* \param fname the name of the file
* \param silent whether print messages during loading
* \param out a loaded data matrix
* \return 0 when success, -1 when failure happens
*/
XGB_DLL int XGDMatrixCreateFromFile(const char *fname,
int silent,
DMatrixHandle *out);
XGDMatrixNumCol()
/*!
* \brief get number of columns
* \param handle the handle to the DMatrix
* \param out The output of number of columns
* \return 0 when success, -1 when failure happens
*/
XGB_DLL int XGDMatrixNumCol(DMatrixHandle handle,
bst_ulong *out);
Here is the repo for my project. I'm using Visual Studio Enterprise 2015 . It's built in "Debug" mode (targeting x64) on Windows 10 Pro (64-bit). x64 binaries for libxgboost.dll can be found here. Although the linked repo does contain a copy of libxgboost.dll.
Try to use the calling convention Cdecl which seems to be used by the DLL.
Also, the signature of the XGDMatrixCreateFromFile function is wrong. The parameter expected is not a pointer to some memory allocated by you, but the function will allocate memory itself and then return the pointer as an output parameter.
Try the following code. Note the use of the the out keyword on the outputPtr parameter in the XGDMatrixCreateFromFile function.
[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, out IntPtr outputPtr);
[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, IntPtr dmatrixColumnsPtr);
static void Main(string[] args)
{
IntPtr dmatrixPtr;
IntPtr dmatrixColumnsPtr = Marshal.AllocHGlobal(10);
int result = XGDMatrixCreateFromFile("C:\\dev\\libs\\xgboost\\demo\\data\\agaricus.txt.test", 0, out dmatrixPtr);
int cols = XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr);
Marshal.FreeHGlobal(dmatrixColumnsPtr);
}
When this works, you can then also simplify the call to get the number of columns by using the ulong datatype:
[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, out IntPtr outputPtr);
[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, out ulong dmatrixColumnsPtr);
static void Main(string[] args)
{
IntPtr dmatrixPtr;
ulong dmatrixColumns;
int result = XGDMatrixCreateFromFile("C:\\dev\\libs\\xgboost\\demo\\data\\agaricus.txt.test", 0, out dmatrixPtr);
int cols = XGDMatrixNumCol(dmatrixPtr, out dmatrixColumns);
}
I am trying to import a driver dll for a piece of equipment my company uses, but I can't seem to get this to work. I am new to c# so please go easy on me. This is related to a post I made yesterday, I am attempting to convert a C program over to C#.
I wrote this code so that I could start to understand PInvoke
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace PInvokeTest {
class Program {
static void Main(string[] args) {
Int32 session_handle = 0;
Byte state_buffer = 0;
Int16 result = 1, PortNum = 1, PortType = 1;
session_handle = TMExtendedStartSession(PortNum, PortType);
result = TMSearch(session_handle, state_buffer, 1, 1, 0xEC);
if (result == 1)
Console.WriteLine("Device Found");
if (result == -201)
Console.WriteLine("Hardware Driver Not Found");
else
Console.WriteLine("Network Error");
Console.ReadKey();
}
[DllImport("IBFS32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 TMExtendedStartSession(Int16 PortNum, Int16 PortType);
[DllImport("IBFS32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern Int16 TMSearch(Int32 session_handle, Byte state_buffer, int p1, int p2, int p3);
}
}
I am trying to use these 2 functions
TMExthendedStartSession http://files.maximintegrated.com/sia_bu/licensed/docs/1-wire_sdk_win/TMEX/exst8l9q.html
and TMSearch
http://files.maximintegrated.com/sia_bu/licensed/docs/1-wire_sdk_win/TMEX/sear1ezy.html
When I run TMExthendedStartSession I get System.AccessViolationException, but when I run TMSearch alone I get a message
"Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in 'C:\PInvokeTest\Debug\PInvokeTest.vshost.exe'."
The function TMSearch does return a value of -201 though.
Any help is appreciated.
In 32 bit Windows, the pascal calling convention maps to stdcall. There is a #define near the top of WinDef.h (or minwindef.h in more modern SDKs) that maps pascal to __stdcall.
On top of that, your parameters are all wrong. It should be like this:
[DllImport("IBFS32.dll")]
public static extern int TMExtendedStartSession(
short PortNum,
short PortType,
IntPtr EnhancedOptions
);
[DllImport("IBFS32.dll")]
public static extern short TMSearch(
int session_handle,
IntPtr state_buffer,
short p1,
short p2,
short p3
);
The state_buffer parameter might perhaps be better declared as byte[]. It's hard to tell from here what the semantics are.
This is the signature of my function in DLL:
int __stdcall myFun( void * const context, const char * const pszFileName, const unsigned int buffSize, void * const pWaveFormatex );
All parameters are [in]. The user should pass a pointer to a WAVEFORMATEX struct through the last parameter. Upon return, it will be filled. All that works very well in C++.
Now, I'm trying for days to use the same DLL from C# and it simply doesn't work. The problem is in the last parameter. Since I do not know C# at all, I would like to ask somebody if this is doable at all. If it is, I would appreciate an example.
One of my last attempts was this:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct WAVEFORMATEX
{
public ushort wFormatTag;
public ushort nChannels;
public uint nSamplesPerSec;
public uint nAvgBytesPerSec;
public ushort nBlockAlign;
public ushort wBitsPerSample;
public ushort cbSize;
}
Note: I also built my DLL written in C++ with the Struct Member Alignment = 1. Maybe I'm stupid, but I thought that Pack = 1 above is related with that in C++, but I have no idea if it is...
[DllImport("myLib.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern int myFun( IntPtr context,
[MarshalAs( UnmanagedType.LPStr )]
string pszFileName,
int bufferSize,
ref IntPtr pWfx );
IntPtr unmanaged_pWfx = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WAVEFORMATEX)));
result = DLLWrapper.myFun(context,
"C:\\video.wmv",
176400,
ref unmanaged_pWfx );
WAVEFORMATEX wfxFormat = (WAVEFORMATEX)Marshal.PtrToStructure( unmanaged_pWfx, typeof(WAVEFORMATEX));
The behavior is undefined. Sometimes it hangs, sometimes it terminates... Something is very wrong. However, the problem is not in the DLL, the problem is on the C# side. Is C# capable of working with pointers at all?
Thanks for any feedback you provide.
EDIT (working C++ code):
void * context;
WAVEFORMATEX wfx;
int success = getContext( &context );
success = myFun( context, "C:\\video.wmv", 176400, &wfx );
The equivalent in C# is:
IntPtr context;
WAVEFORMATEX wfx;
int success = getContext( out context );
success = myFun( context, "C:\\video.wmv", 176400, out wfx );
extern "C" __stdcall int getContext( void ** pContext );
[DllImport("myLib.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int getContext(out IntPtr context);
Well, based on the information you have provided I would say that you need to declare the C# function like this:
[DllImport("myLib.dll")]
public static extern int myFun(
IntPtr context,
string fileName,
uint bufferSize,
out WAVEFORMATEX wfx
);
And call the function like this:
WAVEFORMATEX wfx;
int result = DLLWrapper.myFun(context, #"C:\video.wmv", 176400, out wfx);
There's really no need for manual marshalling of this struct. It's a very simple blittable struct and it is much cleaner to let the framework handle the marshalling.
I am assuming that you are accurate when you state that the final struct parameter does not need to be initialised and its members are filled out by the function.
Packing looks reasonable. I don't think you need to build your DLL in any special way. I hope that you are picking up WAVEFORMATEX from the Windows header files and they already specify packing for that struct.
If you are still stuck then you should show the successful C++ calling code.
Judging from the comments, you still have a bug somewhere in your code. In such a situation, especially when you doubt the interop, it pays to make a simple reproduction to determine whether the interop is the problem, or not. Here is mine:
C++ DLL
#include <Windows.h>
#include <mmsystem.h>
#include <iostream>
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
__declspec(dllexport) int __stdcall myFun(void * const context,
const char * const pszFileName, const unsigned int buffSize,
void * const pWaveFormatex)
{
std::cout << context << std::endl
<< pszFileName << std::endl
<< buffSize << std::endl;
WAVEFORMATEX wfx;
wfx.cbSize = 1;
wfx.nAvgBytesPerSec = 2;
wfx.nBlockAlign = 3;
wfx.nChannels = 4;
wfx.nSamplesPerSec = 5;
wfx.wBitsPerSample = 6;
wfx.wFormatTag = 7;
CopyMemory(pWaveFormatex, &wfx, sizeof(wfx));
return 666;
}
C# console app
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication13
{
class Program
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct WAVEFORMATEX
{
public ushort wFormatTag;
public ushort nChannels;
public uint nSamplesPerSec;
public uint nAvgBytesPerSec;
public ushort nBlockAlign;
public ushort wBitsPerSample;
public ushort cbSize;
}
[DllImport(#"Win32Project1.dll", EntryPoint = "?myFun##YGHQAXQBDI0#Z")]
public static extern int myFun(
IntPtr context,
string fileName,
uint bufferSize,
out WAVEFORMATEX wfx
);
static void Main(string[] args)
{
WAVEFORMATEX wfx;
int result = myFun((IntPtr)42, #"C:\video.wmv", 176400, out wfx);
Console.WriteLine(result);
Console.WriteLine(wfx.cbSize);
Console.WriteLine(wfx.nAvgBytesPerSec);
Console.WriteLine(wfx.nBlockAlign);
Console.WriteLine(wfx.nChannels);
Console.WriteLine(wfx.nSamplesPerSec);
Console.WriteLine(wfx.wBitsPerSample);
Console.WriteLine(wfx.wFormatTag);
Console.ReadLine();
}
}
}
Output
0000002A
C:\video.wmv
176400
666
1
2
3
4
5
6
7
The problem is passing the IntPtr. You're passing stack allocated variable(the one that holds actual pointer) to your code, but you want to pass the pointer. Just remove the "ref" keyword from your code.
I am trying to find the COM port assigned to a USB device, through the registry using Silverlight, and have tried the following:
dynamic WshShell = AutomationFactory.CreateObject("WScript.Shell");
string strRegKeyUSB = #"HKLM\HARDWARE\DEVICEMAP\SERIALCOMM\\Device\USB_COM";
string strCOMValue = WshShell.RegRead(strRegKeyUSB);
This approach usually works 100%, but all Value names under the DEVICEMAP Key is "\Device\XXX"
This causes the the "Path" to not be found, as the "\\" between SERIALCOMM and Device is not seen as valid (Throws Error: "Cannot find File Specified")
This, as far as I can see, only really leaves me with one option - P/Invoke, in Silverlight 5
I am using P/Invoke already for a SerialWrapper Class, to Open, Read, Write the COM Ports, and would like to include only the minimal needed to only read this one Key Value from the Registry - I have tried following some examples I have found, but not being strong in Interop, P/Invoke, etc. I am struggling to find only the portions I need.
If someone could please just give me a basic example, to only accomplish this (I do NOT need to write to the registry, or read QWORDS, or anything else - Only read this string value from only this specific key)
I have tried following the following post (Marshal.PtrToStructure in Silverlight) and it's answer, in relation to this (http://www.pinvoke.net/default.aspx/winspool.enumports), but have not been able to get this working, Most likely form a lack of REALLY understanding ;-)
Here's a simple desktop application that reads a REG_SZ value. It's crude and simple. It will read the value that you want. You may have to adapt it to Silverlight. I cannot help you there!
I hope this is useful:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
namespace ConsoleApplication1
{
internal static class NativeMethods
{
public const int ERROR_SUCCESS = 0;
public const uint HKEY_LOCAL_MACHINE = 0x80000002;
public const int KEY_READ = 0x20019;
[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
public static extern int RegOpenKeyEx(
UIntPtr hKey,
string subKey,
int ulOptions,
int samDesired,
out UIntPtr hkResult
);
[DllImport("advapi32.dll")]
public static extern int RegCloseKey(
UIntPtr hKey
);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
public static extern int RegQueryValueEx(
UIntPtr hKey,
string lpValueName,
int lpReserved,
IntPtr type,
IntPtr lpData,
ref int lpcbData
);
}
internal static class RegistryWrapper
{
private static void checkErrorCode(int errorCode)
{
if (errorCode != NativeMethods.ERROR_SUCCESS)
throw new Win32Exception(errorCode);
}
public static string ReadRegString(UIntPtr rootKey, string subKey, string name)
{
UIntPtr hkey;
checkErrorCode(NativeMethods.RegOpenKeyEx(rootKey, subKey, 0, NativeMethods.KEY_READ, out hkey));
try
{
int cbData = 0;
checkErrorCode(NativeMethods.RegQueryValueEx(hkey, name, 0, IntPtr.Zero, IntPtr.Zero, ref cbData));
IntPtr ptr = Marshal.AllocHGlobal(cbData);
try
{
checkErrorCode(NativeMethods.RegQueryValueEx(hkey, name, 0, IntPtr.Zero, ptr, ref cbData));
return Marshal.PtrToStringUni(ptr, cbData / sizeof(char)).TrimEnd('\0');
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
finally
{
checkErrorCode(NativeMethods.RegCloseKey(hkey));
}
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(RegistryWrapper.ReadRegString((UIntPtr)NativeMethods.HKEY_LOCAL_MACHINE, #"HARDWARE\DEVICEMAP\SERIALCOMM", #"\Device\Serial0"));
}
}
}
Update
It seems that AllocHGlobal and FreeHGlobal are not available on Silverlight. You can p/invoke to LocalAlloc and LocalFree instead. Or you could use CoTaskMemAlloc and CoTaskMemFree. Here's what the former looks like:
[DllImport("kernel32.dll", SetLastError=true)]
static extern IntPtr LocalAlloc(uint uFlags, UIntPtr uBytes);
[DllImport("kernel32.dll", SetLastError=true)]
static extern IntPtr LocalFree(IntPtr hMem);
Define LMEM_FIXED like this:
const uint LMEM_FIXED = 0x0000;
Then replace the call to AllocHGlobal with this:
IntPtr ptr = LocalAlloc(LMEM_FIXED, cbData);
And replace the call to FreeHGlobal with this:
LocalFree(ptr);
A BIG thank you to #Dave Heffernan,
I got this to work FINALLY...
I Added the following code within the RegistryWrapper class in Dave's Answer:
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LocalAlloc(uint uFlags, int size);
internal static IntPtr AllocHGlobal(int size)
{
uint LPTR = (uint)0x0040;
IntPtr hGlobal = LocalAlloc(LPTR, size);
if (hGlobal == IntPtr.Zero)
{
throw new OutOfMemoryException("Unmanaged memory was not allocated.");
}
return hGlobal;
}
This works around the limitation of Marshal.AllocHGlobal not being available in Silverlight.
I then also just changed the reference to Marshal.AllocHGlobal to the local AllocHGlobal method above.
I have a problem with my project:
In dll c++:
extern "C" __declspec(dllexport) int results(char* imgInput, void* tree)
{
struct kd_node* nodeTree = new(tree)kd_node ; // new kd_tree with data from memory address
...
...
int ret = atoi(retValueStr.c_str());
return ret;
}
extern "C" __declspec(dllexport) void* buildKDTree(char* folder)
{
struct kd_node* kd_root;
....
feature *LFData = listFeat.data();
kd_root = kdtree_build(LFData,listFeat.size());
void* address_kdtree = (void*)&kd_root; // get memory address of kd_tree
return address_kdtree;
}
and I use to dllimport in c#:
[DllImport(#"kdtreeWithsift.dll", EntryPoint = "buildKDTree", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern void* buildKDTree(byte[] urlImage);
[DllImport(#"kdtreeWithsift.dll", EntryPoint = "results", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
[return:MarshalAs(UnmanagedType.I4)]
public unsafe static extern int results(byte[] imgInput, void* tree);
static unsafe void Main()
{
string urlImg1 = "C:/Users../test img/1202001T1.jpg";
string urlImg = "C:/export_features";
try
{
IntPtr result;
int result1;
result1 = results(convertStringToByte(urlImg1), 5, buildKDTree(convertStringToByte(urlImg))); // this error
Console.WriteLine("results = %d",result1);
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
}
}
when i run the program, this program show error :
Attempted to read or write protected memory. This is often an indication that other memory is corrupt
what error do you know and how to resolved ?
thank you!
You don't need a convertStringToByte method here. You can tell the runtime to marshal your string as a char *. Also, I would suggest that you make the method return an IntPtr, like this:
[DllImport(#"kdtreeWithsift.dll", EntryPoint = "buildKDTree",
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr buildKDTree([MarshalAs(UnmanagedType.LPStr)]string urlImage);
[DllImport(#"kdtreeWithsift.dll", EntryPoint = "results",
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
[return:MarshalAs(UnmanagedType.I4)]
public static extern int results([MarshalAs(UnmanagedType.LPStr)]string imgInput, IntPtr tree);
You can then call it with:
IntPtr tree = buildKDTree(urlImg);
int result1 = results(urlImg, 50, tree);
Console.WriteLine("results = {0}",result1);
Well, for one thing, the C function is called buildKDTree, but you are importing it in the C# code with entry point "buildKDTreeWithFeatures". Try making these consistent and see if you get better results.
I try to call it :
IntPtr tree = buildKDTree(urlImg);
int result1 = results(urlImg, 50, tree);
Console.WriteLine("results = {0}",result1);
but it is not your fault where you said.
I think the variable intPtr tree in function results([MarshalAs(UnmanagedType.LPStr)]string imgInput, IntPtr tree); that caused the error
I think its similar problem due to char* parameters, in my own problem thanks to this below link question solves the problem.
So your only solution is to pass the string parameters as IntPtr.
Allocate the memory with Marshal.StringToHGlobalAnsi
Attempted to read or write protected memory with dllimport in c#