CoCreateInstance() -858993460 (in comip.h) C++ - c#

I will spend a little time explaining my project stucture:
There are three dlls:
mclController.dll - a third party dll written in C# to control the hardware..
MCLWrapper.dll - I wrote this ll in C# such that it will be working as a COM to expose the mclControl.dll to a native C++ dll.
ThorDetectorSwitch.dll - I wrote this dll with native C++.
Structure:
The ThorDetectorSwitch.dll calls the MCLWrapper.dll which wraps mclController.dll.
I am implementing a small testing console application in C++, TDSTest.exe to call ThorDetecttorSwitch.dll.
So it basically works like this: TDSTest.exe -> ThorDetectorSwitch.dll -> MCLWrapper -> mclController.dll
Some code:
-How TDSTest.exe (Windows console application, built with x64 configuration) calls ThorDetectorSwitch.dll:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <math.h>
#include <windows.h>
#include "TDSTest.h"
typedef long (*TDSFindDevices)(long&);
typedef long (*TDSGetParam)(const long, double&);
typedef long (*TDSTeardownDevice)();
typedef long (*TDSStartPosition)();
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
if (argc < 2)
{
cout<<"This is ThorDetecttorSwitch test program."<<endl;
return 1;
}
HINSTANCE hInst = LoadLibrary(_T(".\\Modules_Native\\ThorDetectorSwitch.dll"));
if( hInst == NULL )
{
DWORD err = GetLastError();
cout<<"Error loading ThorDetectorSwitch.dll. Program exiting..."<<endl;
return 1;
}
}
-Constructor of the ThorDetectorSwitch.dll EDITTED! on 06/15/2013, Central Time 19:41
ThorDetectorSwitch::ThorDetectorSwitch() :_mcSwitch(ComHelper(__uuidof(MCLControlClass)))
{
CoInitialize(NULL);
MCLWrapper::MCLControlPtr mclSmartPtr;
HRESULT hr = CoCreateInstance(__uuidof(MCLWrapper::MCLControlClass), NULL, CLSCTX_ALL, __uuidof(MCLWrapper::MCLControl), (void**)&mclSmartPtr); // program breaks right here!!!
_mcSwticth = mclSmartPtr;
_A = WstringToBSTR(L"A");
_B = WstringToBSTR(L"B");
_C = WstringToBSTR(L"C");
_D = WstringToBSTR(L"D");
_deviceDetected = FALSE;
}
The MCLWrapper that makes a COM object
// C# COM wrapper
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using mcl_RF_Switch_Controller64;
using System.Runtime.InteropServices;
// for function reference see miniCircuit RF controller manual
namespace MCLWrapper
{
[Guid("7C312A7C-2E77-4de7-A76F-990F268AB818")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface MCLControl
{
[DispId(1)]
void Connect(string SerialNumber);
[DispId(2)]
void Set_Switch(string SwitchName, int Val);
[DispId(3)]
void Set_SwitchesPort(byte binVal);
[DispId(4)]
void GetSwitchesStatus(int statusRet);
[DispId(5)]
void Disconnect();
};
[Guid("BEC33A1D-BB98-4332-B326-92D480ECC246"),
ClassInterface(ClassInterfaceType.None)]
public class MCLControlClass : MCLControl
{
private USB_RF_SwitchBox _sb = new USB_RF_SwitchBox();
public void Connect(string SerialNumber)
{
_sb.Connect(ref SerialNumber);
}
public void Set_Switch(string SwitchName, int Val)
{
_sb.Set_Switch(ref SwitchName, ref Val);
}
public void Set_SwitchesPort(byte binVal)
{
_sb.Set_SwitchesPort(ref binVal);
}
public void GetSwitchesStatus(int statusRet)
{
_sb.GetSwitchesStatus(ref statusRet);
}
public void Disconnect()
{
_sb.Disconnect();
}
}
}
My Problem:
When the TDSTest is executed, it first hits
HINSTANCE hInst = LoadLibrary(_T(".\\Modules_Native\\ThorDetectorSwitch.dll"));
then it breaks at:
hr = CoCreateInstance(......) in the ThorDetectorSwitch.cpp
hr = -858993460 is the return;
A few additionals
I am kept be told it was because CoInitialized() did not get called, and that is the reason, but I feel that is not the reason because this ThorDetectorSwitch.dll works perfectly fine with another application, and I beleive I have called CoInitialized() in my code.
I have registered my MCLWrapper.dll with regasm MCLWrapper.dll /tlb:MCLWrapper.tlb /codebase
Debugger output: "Attempting managed execution inside OS Loader lock. Do not attempt to run managed code inside a DllMain or image initalization function since doing so can cause the application of hang."
So right now I have no idea what direction I should go, and I have been struglling with this problem for days. So I really hope someone can give some pointers for me. Thanks!

You need to lazily construct your object instead of have it as a global variable created on DLL load.
Maybe you could have your DLL provide an Initialize() function that would be called by the client? Assuming you can't make your object "not global at all" of course.

Related

SEHException (0x80004005) when using JNI to run C# code

I have a project written in Kotlin, and I want to use a library written in C#. So I used the JNI to make a "proxy" in C++ witch make the link between C# and the JVM.
I was able to load the library in Kotlin but I have this error when I call a function:
Fatal error. System.Runtime.InteropServices.SEHException (0x80004005): External component has thrown an exception.
at <Module>.Java_Authenticator_authenticate(JNIEnv_*, _jobject*, _jstring*, _jstring*)
:run (Thread[Execution worker for ':' Thread 2,5,main]) completed. Took 1.965 secs.
This is my Java class witch use the library:
public class Authenticator {
static {
System.loadLibrary("CppProxy");
}
public native boolean authenticate(String username, String password);
public void runLib() {
System.out.println("run");
boolean valid = authenticate("admin", "admin");
if(valid) {
System.out.println("Valid");
}
else {
System.out.println("No valid");
}
}
}
This is the Authenticator.h file in C++ project, generated automatically with the command javac -h:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Authenticator */
#ifndef _Included_Authenticator
#define _Included_Authenticator
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Authenticator
* Method: authenticate
* Signature: (Ljava/lang/String;Ljava/lang/String;)Z
*/
JNIEXPORT jboolean JNICALL Java_Authenticator_authenticate
(JNIEnv *, jobject, jstring, jstring);
#ifdef __cplusplus
}
#endif
#endif
This is my CppProxy.cpp file:
#include "pch.h"
#include "CppProxy.h"
#include <string.h>
#include "Authenticator.h"
String^ toString(const char* chars) {
int len = (int)strlen(chars);
array<unsigned char>^ a = gcnew array<unsigned char>(len);
int i = 0;
while (i < len) {
a[i] = chars[i];
i++;
}
return System::Text::Encoding::UTF8->GetString(a);
}
bool authenticate(const char* username, const char* password) {
return LibreHardwareMonitorWrapper::SharpAuthenticator::SharpAuthenticated(toString(username), toString(password));
}
JNIEXPORT jboolean JNICALL Java_Authenticator_authenticate
(JNIEnv* env, jobject c, jstring username, jstring password) {
jboolean isCopyUsername;
const char* c_username = env->GetStringUTFChars(username, &isCopyUsername);
jboolean isCopyPassword;
const char* c_password = env->GetStringUTFChars(password, &isCopyPassword);
jboolean result = authenticate(c_username, c_password);
// cleaning
env->ReleaseStringUTFChars(username, c_username);
env->ReleaseStringUTFChars(username, c_password);
return result;
}
And this is my C# code:
namespace LibreHardwareMonitorWrapper
{
public static class SharpAuthenticator
{
public static bool SharpAuthenticated(String username, String password)
{
return username == "admin" && password == "admin";
}
}
}
I'm using the oracle JDK 17 and the C# project is currently using .NET6.
Cpp project target x64 platform and C# project Any CPU.
The Cpp project is build in a folder call "lib" witch is inside java.library.path.
CppProxy has for reference LibreHardwareMonitorWrapper.
I tried to run .\gradlew run and expected to see Valid but I have an error in my external function at execution.
Finally found what was the problem. I could not find the CLR option in properties of C# project, whereas it's crucial for running C# code in C++.
So I think .net6 is not yet compatible with this option, I tried with .net framework 4.x and it works.
Also, you should know that it is necessary to put the assemblies of C# project in the /bin of JDK.

How to call C++ code, and the code it calls, from C#

TL;DR
I have legacy c++ code which does stuff (sometimes returns stuff), calls other cpp code, but is not a full class/obj. This code I cannot alter. I am making fresh c# code which I am looking to call the c++ code from. I don't understand whether to create a dll that calls the original legacy c++, or create a CLR?? which also calls the legacy cpp. Below I have example code that I have implemented (with problems).
Main
I have legacy.cpp and legacy.h which I can not alter.
This is not a class/object and only has public functions, values, and #defines.
legacy.cpp and .h both #include other files and cpp libraries to do its job.
I have a new project where I can add C#, C++ code
I am having trouble understanding what I need to do/research in order to call any of the functions defined in legacy.cpp (or the values/defines) from within my new C# code.
Some of what I have looked at include
Managed CLR wrappers
https://drthitirat.wordpress.com/2013/06/03/use-c-codes-in-a-c-project-wrapping-native-c-with-a-managed-clr-wrapper/
https://web.archive.org/web/20140806022309/http://blogs.msdn.com/b/borisj/archive/2006/09/28/769708.aspx
DLLs??
How to call C++ DLL in C#
CLR
I have currently tried to create a CLR (thought I feel like it is not what I need in this situation), but I had problems in the clr_wrapper.cpp, it could not find the reference to foo()
//Wrapper.cpp
#include "Wrapper.h"
#include "abs\path\to\legacy\code\legacy.h"
#include "abs\path\to\legacy\code\legacy.cpp"
int foo_Wrapper()
{
return foo(); //int foo() is declared in legacy.h and defined in legacy.cpp
}
#pragma once
#include "abs\path\to\legacy\code\legacy.h"
#include "abs\path\to\legacy\code\legacy.cpp"
using namespace System; //What things use this?
//Can I just prepend System:: to whatever needs it?
namespace Wrapper {
public ref class Wrapper
{
public:
int foo_Wrapper();
};
}
the foo_Wrapper() is not able to call foo().
My confusion with this method is that it looks like I would need to make the clr wrapper an object class with member functions that will be called as needed. Leading to a syntax of obj.foo(). Is this what needs to be done if I chose to do some sort of CLR wrapper?
DLL
I have also looked at making this all a dll like in (How to call C++ DLL in C#)
However I am confused on setting this up. My current idea is to have a cpp dll call the original cpp (ie create legacyDll.dll which would make calls to foo(), then my main c# would call the __declspec(dllexport) functions defined within extern "C" {}
current setup (from "How to call c dll in c sharp")
dllmain.cpp
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <iostream>
#include <Windows.h>
using namespace std;
extern "C"
{
__declspec(dllexport) void bar_Dll()
{
cout << "calling bar() in legacy code" << endl;
}
__declspec(dllexport) int foo_Dll()
{
cout << "calling foo() in legacy code" << endl;
//realistically I would have,
//return foo()
}
}
Class1.cs
using System;
using System.Runtime.InteropServices;
namespace Test_DLL_Calling
{
class Class1
{
[DllImport("dllmain.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void bar_Dll();
[DllImport("dllmain.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int foo_Dll();
public static void Main(string[] arg)
{
bar_Dll(); //The specified module could not be found (Exception)
Console.WriteLine(foo_Dll()); //Im guessing this will also ^^
}
}
}
This part I don't follow. What and why are the attributes done the way they are?
Alright, so you have a header and cpp which you need to use. In order to use it you have to have make the c++ into C code. This is pretty much what you see in the DLL example code that you showed. However, I do suggest that you remove the includes from the header as I'm unsure how that would translate to the C code. Put the includes in the cpp files instead.
I find it rather difficult to answer this questions other than just showing a whole bunch of example code. Full code in: https://github.com/ze413X/Cpp-Code-Gems/ Where "CSharpExampleUsingCpp" calls from MainWindow.xaml.cs the "DLLExample" which uses the file in the directory includes and source.
DLL:
The header which is exposing functions to be used:
#pragma once
#define DLLExport _declspec(dllexport)
extern "C" DLLExport void __cdecl GetCppText(char* str, int* strLength);
extern "C" DLLExport void __cdecl DLLPrint();
.cpp
#include "../includes/DLLExampleCode.h"
#include <string>
#include <iostream>
void __cdecl GetCppText(char* str, int* strLength)
{
std::string text = "This is called from within the DLL.\0";
if (*strLength < text.length() || str == nullptr)
{
return;
}
memset((void*)str, 0, (*strLength) * sizeof(char));
strcpy_s(str, *strLength,text.c_str());
*strLength = text.length();
}
void __cdecl DLLPrint()
{
std::cout << "This is printed from inside DLLExample.dll.\n";
}
C#:
using System.Runtime.InteropServices;
namespace CSharpExampleUsingCpp
{
public partial class MainWindow : Window
{
const string PATH = "DLLExample.dll";
[DllImport(PATH, CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void GetCppText(byte[] str, out System.Int32 strLength);
....
private void CppInteropButton_Click(object sender, RoutedEventArgs e)
{
System.Int32 size = 256;
System.Byte[] str = new byte[size];
for (int i = 0; i < size; i++)
{
str[i] = (byte)'1';
}
GetCppText(str, out size);
string result = System.Text.Encoding.UTF8.GetString(str, 0, size);
CppInteropButtonTextBox.Text = result;
}
Although, rereading my solution of obtaining a string might not be the best way of doing it. You could probably marshal that thing to avoid all this stupid char* conversions. I probably had some good reason at that point in time when I wrote it. That should be much easier to google though.

Is gcroot and /clr mixed mode and a C++ wrapper the shortest path from pure C to C#?

So I am writing a plug-in DLL which is pure C (and a heap of foreign includes), but most of the real code is in an existing C# class library. I'm looking for the shortest path from C (not C++) to C#. The foreign includes are not C++ safe.
There are heaps of samples around for C++, not much for pure C.
It seems I should be able to compile the whole DLL as /clr but compile the C as not; then include in the same DLL a C++ wrapper that presents a C API but contains managed code to call the C# class.
So instantiate the C# class and hang onto it in a gcroot in a C++ class, and pass the C++ class pointer as a void* back for the the C code to keep for future calls.
Quite a few details to get right, but not all that much code. Is there a better way?
Thought it was time to add a bit of code.
// Wrapper.h
#pragma once
// API for call by C
#ifdef __cplusplus
extern "C" {
#endif
void* wrap_create();
void wrap_doit(void* wrapper, char* input, char* output, int maxlen);
#ifdef __cplusplus
}
#endif
// Wrapper.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <vcclr.h>
#include "Wrapper.h"
using namespace System;
class Wrapper {
public:
gcroot<Wrappee::Evaluator^> eval;
Wrapper() {}
};
void* wrap_create() {
Wrapper* w = new Wrapper();
w->eval = gcnew Wrappee::Evaluator();
return w;
}
void wrap_doit(void* wrapper, char* input, char* output, int maxlen) {
Wrapper* w = (Wrapper*)wrapper;
String^ s = w->eval->Doit(gcnew String(input));
pin_ptr<const wchar_t> wch = PtrToStringChars(s);
wcstombs(output, wch, maxlen);
}
// Wrappee.cs
using System;
namespace Wrappee {
public class Evaluator {
string _s;
public static Evaluator Create() {
return new Evaluator {
_s = "wrapped evaluator"
};
}
public string Doit(string s) {
return _s + ":" + s;
}
}
}
Why wouldn't that work? The code is based on this link: https://msdn.microsoft.com/EN-US/library/481fa11f%28v=VS.140,d=hv.2%29.aspx.
The answer is no, that won't work. The managed class depends on the CLR runtime, which needs to be hosted by the application. For a managed app that happens automatically (mscoree.dll during startup), but for a native app there is no host so no CLR.
So we have to provide one. As #hanspassant helpfully pointed out, this is "Reverse P/Invoke" and it really is different. You have to get there by the COM hosting interfaces, specifically ICLRMetaHost.
And the good news is that there is a sample here to show how it's done: https://code.msdn.microsoft.com/windowsdesktop/CppHostCLR-e6581ee0.
There are other samples too: search for CppHostCLR.

Bidirectional communication between unmanaged C++ (no CLR) and managed C#

I am working with a C++ MFC plug-in dll which is automatically launched from an off-the-shelf application at runtime. I need to modify the plugin to support bidirectional communication with a .NET based C# application.
I have access to the plugin source code but I am not able to change the C++ project to use /clr. I get a runtime error from the off-the-shelf application:
'r6033 attempt to use msil code from this assembly during native code initialization'
I have tried to use "#pragma unmanaged" around the Main method with no luck. So I decided to go the COM route.
I have successfully created a COM based C# dll with a UI and methods implemented which I can call from C++. That gets me one direction. I need to implement a way of making calls to the C++ plugin from the C# application. I started down the path of events. I created an event in C# which are raised on the C# side from the new UI but I was not able to figure out how to create and hook to the events on the C++ side. Any help would be appreciated.
Here is the C# COM Code:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.IO;
namespace MyInterop
{
[Guid("03AD5D2D-2AFD-439f-8713-A4EC0705B4D9")]
public interface IMyDotNetInterface
{
void ShowCOMDialog();
}
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("63058ba6-5675-43d6-b38b-fd261fe64950")]
public interface IIntelliWaveEvents
{
[DispId(1)]
void CallIWave(string a_IWaveCommand);
}
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IIntelliWaveEvents))]
[Guid("0490E147-F2D2-4909-A4B8-3533D2F264D0")]
public class MyDotNetClass : IMyDotNetInterface
{
public IIntelliWaveEvents callbackObject;
// Need a public default constructor for COM Interop.
public MyDotNetClass()
{ }
public void ShowCOMDialog()
{
MainForm frm = new MainForm()
{
StartPosition = FormStartPosition.CenterScreen,
TopMost = true
};
frm.CallIWave += new MainForm.CallIWaveEventHandler(frm_CallIWave);
frm.Show();
}
void frm_CallIWave(object sender, Events.IWaveEvents.CallIWaveEventArgs e)
{
string filename = #"C:\Companies\ComEvent.txt";
File.WriteAllText(filename, "COM Event Called at " + DateTime.Now);
//Pass the event to c++
if (callbackObject != null)
{
callbackObject.CallIWave(e.Message);
}
}
}
}
Here is the interface WaveDLL_PAI.cpp code:
#include "stdafx.h"
#include "WaveDLL_PAI.h"
#include "IUserPrograms1.h"
using namespace std;
#import "C:\Program Files\SampleCOM\com.MyInterop.tlb" named_guids raw_interfaces_only
using namespace MyInterop;
//------------------------------------------------------------------------
// This function must exist in all PlugIn(s).
// It creates an instance of the API class and returns a pointer to it.
HRESULT CreateInstance(void **p)
{
*p = new CWaveDLL_PAI();
return (*p != NULL);
}
//---------------------------------------------------------------------------------------------------
// Initialize native variables here
CWaveDLL_PAI::CWaveDLL_PAI() : CWaveDLL_BaseI()
{
}
//---------------------------------------------------------------------------------------------------
// deallocate any memory here
CWaveDLL_PAI::~CWaveDLL_PAI()
{
Release();
}
//---------------------------------------------------------------------------------------------------
// This function releases any memory allocated for this class
ULONG CWaveDLL_PAI::Release()
{
return 0;
}
//---------------------------------------------------------------------------------------------------
// This function must be used to create the class including memory allocation.
// Allocate memory or objects here only.
// Do not display any window or dialog here
ULONG CWaveDLL_PAI::Create(CWnd *pParent, void *a, void *b, void *c)
{
CoInitialize(NULL); //Initialize all COM Components
MyInterop::IMyDotNetInterfacePtr pDotNetCOMPtr;
HRESULT hRes = pDotNetCOMPtr.CreateInstance(MyInterop::CLSID_MyDotNetClass);
if (hRes == S_OK)
{
BSTR str;
pDotNetCOMPtr->ShowCOMDialog(); //call .NET COM exported function ShowDialog ()
}
CoUninitialize(); //DeInitialize all COM Components
return true;
}
//---------------------------------------------------------------------------------------------------
// This function gives the PlugIn access to data and controls
// This function must be defined and have the code listed below.
long CWaveDLL_PAI::SetData(CUserControl *ctrl, SIntelliWaveDataExt *data, LPCTSTR path)
{
CWaveDLL_BaseI::SetData(ctrl,data,path);
return true;
}
Here is the interface WaveDLL_PAI.h Code:
#include "WaveDLL_BaseI.h"
class AFX_EXT_CLASS CWaveDLL_PAI : public CWaveDLL_BaseI
{
public:
int MyVariable;
CWaveDLL_PAI();
~CWaveDLL_PAI();
int MyFunction(int hello = 0);
ULONG Release();
ULONG Create(CWnd *pParent=0, void *a = 0, void *b = 0, void *c = 0);
long SetData(CUserControl *ctrl, SIntelliWaveDataExt *data, LPCTSTR path = 0);
long Execute(LPCTSTR cmd, void *a = 0, void *b = 0, void *c = 0);
};
Here is the WaveDLL_PA.cpp Code:
#include "stdafx.h"
#include <afxdllx.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
HINSTANCE hInstanceOptic01;
static AFX_EXTENSION_MODULE WaveDLL_PADLL = { NULL, NULL };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Remove this if you use lpReserved
UNREFERENCED_PARAMETER(lpReserved);
hInstanceOptic01 = hInstance;
if (dwReason == DLL_PROCESS_ATTACH)
{
TRACE0("WaveDLL_PA.DLL Initializing!\n");
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(WaveDLL_PADLL, hInstance))
return 0;
// Insert this DLL into the resource chain
// NOTE: If this Extension DLL is being implicitly linked to by
// an MFC Regular DLL (such as an ActiveX Control)
// instead of an MFC application, then you will want to
// remove this line from DllMain and put it in a separate
// function exported from this Extension DLL. The Regular DLL
// that uses this Extension DLL should then explicitly call that
// function to initialize this Extension DLL. Otherwise,
// the CDynLinkLibrary object will not be attached to the
// Regular DLL's resource chain, and serious problems will
// result.
new CDynLinkLibrary(WaveDLL_PADLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("WaveDLL_PA.DLL Terminating!\n");
// Terminate the library before destructors are called
AfxTermExtensionModule(WaveDLL_PADLL);
}
return 1; // ok
}

System.AccessViolationException thrown by Visual C# on call to Lapack inside wrapped C++\CLI dll

I have written some code in native C++ which makes calls to fortran routines of the blas and lapack library (linked as dll's). The native code runs fine, with no compiler or runtime errors or warnings.
Now, I was trying to wrap the native C++ into a dll to use in the .NET framework, so I started a Visual C++ project, wrote a wrapper ref class, compiled this into a dll and included that dll into a C# project.
After I finally managed to get the C# project to compile, I tried to run it. But I get a runtime error at the first call to a lapack routine! (i.e. at the line dpbtrf_( &LOWER, &n, &izero, D.data(), &ione, &info ); in Test.cpp)
The error says:
System.AccessViolationException was unhandled
Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Source=DotNetTest
Am I missing some compiler option?
Or is there really corrupt memory which the native C++ compiler\runtime did not see?
Any tips on how to debug this?
Thanks a lot!
Here's a tiny reproduction that generates the same problem as the original code (which is too extensive to post here):
the native C++ Test.h:
#ifndef TEST_H_INCLUDED
#define TEST_H_INCLUDED
#include <vector>
namespace NativeTest
{
class Test
{
public:
Test( int size );
~Test();
void set( int i, double d );
double get( int i ) const;
int chol();
private:
std::vector<double> D;
int n;
}; // class Test
} // namespace NativeTest
#endif // TEST_H_INCLUDED
the native C++ Test.cpp (included in the VC++ project) (!EDITTED with __cdecl):
#include "Test.h"
using namespace NativeTest;
const int ione = 1;
const int izero = 0;
const char LOWER = 'L';
extern "C"
{
// factorization for banded matrix
void __cdecl dpbtrf_( const char *UPLO, const int *N, const int *KD,
double *AB, const int *LDAB, int *INFO );
}
Test::Test( int size ) : n( size )
{ D.resize( n ); }
Test::~Test() { }
void Test::set( int i, double d ) { D[ i ] = d; }
double Test::get( int i ) const { return D[ i ]; }
int Test::chol()
{
int info = 0;
dpbtrf_( &LOWER, &n, &izero, D.data(), &ione, &info );
return info;
}
The C++\CLI wrapper:
// TestNet.h
#pragma once
#include "Test.h"
using namespace System;
namespace DotNetTest {
public ref class TestNet
{
public:
TestNet( int size ) { test = new NativeTest::Test( size ); }
~TestNet() { this->!TestNet(); }
!TestNet() { delete test; test = NULL; }
void set( int i, double d ) { test->set( i, d ); }
double get( int i ) { return test->get( i ); }
int chol() { return test->chol(); }
protected:
NativeTest::Test * test;
};
}
The C# call:
DotNetTest.TestNet t = new DotNetTest.TestNet(2);
t.set(0, 2);
t.set(1, 3);
int info = t.chol();
I got it fixed, at least for the test code posted here. I wrongly added the gcc-compiled lapack\blas binaries, the same as I used for my original project (which also used gcc).
Today, I downloaded the precompiled binaries for windows from here, put those in the bin folder of my C# project (together with the 3 MinGW dll's: libgcc_s_dw2-1.dll, libgfortran-3.dll and libquadmath-0.dll) and made sure the Visual C++\CLI project used the same libraries to link to (by setting the Additional Link Directory to the C# bin folder). This fixed it, and I got the result I wanted (no access violation and the calculation was correct).
I also removed the /clr flag in the compile options for the Test.cpp file, and switch the 'Use precompiled headers' off for that file.

Categories