I'm new to C++ CLI coming from unmanaged C++ world.
I'm getting this error:
candidate function(s) not accessible
when I pass a std::string as part of the method argument.
Here's the exact code:
Lib Project (compiled as .dll project)
//Lib.h
#pragma once
public ref class Lib
{
public:
Lib(void);
public:
void Extract( std::string& data_ );
};
//Lib.cpp
#include "Lib.h"
Lib::Lib(void)
{
}
void Lib::Extract( std::string& data_ )
{
data_.empty();
}
LibTest Project (compiled as application.exe)
// LibTest.h
#pragma once
ref class LibTest
{
public:
LibTest(void);
};
// LibTest.cpp
#include "LibTest.h"
LibTest::LibTest(void)
{
Lib^ lib = gcnew Lib;
lib->Extract( std::string("test") );
}
int main()
{
return 0;
}
Compiler Error:
1>------ Build started: Project: LibTest, Configuration: Debug Win32 ------
1>Compiling...
1>LibTest.cpp
1>.\LibTest.cpp(7) : error C3767: 'Lib::Extract': candidate function(s) not accessible
The problem is that std::string will compile as a internal (non public) type. This is actually a change in VS 2005+:
http://msdn.microsoft.com/en-us/library/ms177253(VS.80).aspx:
Native types are private by default outside the assembly
Native types now will not be visible outside the assembly by default. For more information on type visibility outside the assembly, see Type Visibility. This change was primarily driven by the needs of developers using other, case-insensitive languages, when referencing metadata authored in Visual C++.
You can confirm this using Ildasm or reflector, you will see that your extract method is compiled as:
public unsafe void Extract(basic_string<char,std::char_traits<char>,std::allocator<char> >* modopt(IsImplicitlyDereferenced) data_)
with basic_string being compiled as:
[StructLayout(LayoutKind.Sequential, Size=0x20), NativeCppClass, MiscellaneousBits(0x40), DebugInfoInPDB, UnsafeValueType]
internal struct basic_string<char,std::char_traits<char>,std::allocator<char> >
Note the internal.
Unfortunately you are then unable to call a such a method from a different assembly.
There is a workaround available in some cases: You can force the native type to be compiled as public using the make_public pragma.
e.g. if you have a method Extract2 such as:
void Extract2( std::exception& data_ );
you can force std::exception to be compiled as public by including this pragma statement beforehand:
#pragma make_public(std::exception)
this method is now callable across assemblies.
Unfortunately make_public does not work for templated types (std::string just being a typedef for basic_string<>)
I don't think there is anything you can do to make it work. I recommend using the managed type System::String^ instead in all your public API. This also ensures that your library is easily callable from other CLR languages such as c#
if you simply must access the internal methods another work around would be making the projects as Friend Assemblies like that:
//Lib Project
#pragma once
//define LibTest as friend assembly which will allow access to internal members
using namespace System;
using namespace System::Runtime::CompilerServices;
[assembly:InternalsVisibleTo("LibTest")];
public ref class Lib
{
public:
Lib(void);
public:
void Extract( std::string& data_ );
};
//LibTest Project
#pragma once
#using <Lib.dll> as_friend
ref class LibTest
{
public:
LibTest(void);
};
In addition to the solutions described above, one can subclass the templated type to obtain a non-templated type, and include its definition in both projects, thus overcoming some of the problems mentioned above.
Related
I have an old application written in C++ using Visual Studio 2008 that uses COM to use a DLL written in C# using Visual Studio 2012 to display Crystal Reports reports. The VS2012 library is much more complicated than it needs to be, and the method used to access it from the C++ application is also overly complicated. So, as an exercise, I want to write a much simpler VS2012 library to display the reports and then use that library from a C++ application.
I am beginning with a trivial library and trying to make sure I can use it. I am not succeeding. Here is the library's code:
namespace ComVisibleSample
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("83F56EB3-086E-4F81-9FD4-A89ECB708F3E")]
[ProgId("ComVisibleSample.ComVisibleSample")]
[ComDefaultInterface(typeof(IComVisibleSample))]
public class ComVisibleSample : IComVisibleSample
{
public ComVisibleSample() {}
public int DoSomething()
{
return 42;
}
}
}
I created a C++ console application in VS2012 and added a #import directive to import this library. That compiled successfully. Here is the .tlh file that it generated:
// Created by Microsoft (R) C/C++ Compiler Version 11.00.50727.1 (3903bee7).
//
// c:\rad-con tools\trunk\crystalreportssample\consoleapplication1\debug\comvisiblesample.tlh
//
// C++ source equivalent of Win32 type library C:\Rad-Con Tools\trunk\ComVisibleSample\bin\Debug\ComVisibleSample.tlb
// compiler-generated file created 04/23/19 at 12:48:46 - DO NOT EDIT!
#pragma once
#pragma pack(push, 8)
#include <comdef.h>
namespace ComVisibleSample {
//
// Forward references and typedefs
//
struct __declspec(uuid("adffb523-f1ef-4967-9e96-c3ad943d5d97"))
/* LIBID */ __ComVisibleSample;
struct /* coclass */ ComVisibleSample;
//
// Type library items
//
struct __declspec(uuid("83f56eb3-086e-4f81-9fd4-a89ecb708f3e"))
ComVisibleSample;
// interface _Object
} // namespace ComVisibleSample
#pragma pack(pop)
No .tli file was generated.
Here's the program where I'm trying to use the type library:
#include "stdafx.h"
#import "C:\Rad-Con Tools\trunk\ComVisibleSample\bin\Debug\ComVisibleSample.tlb"
int _tmain(int argc, _TCHAR* argv[])
{
ComVisibleSample::ComVisibleSample sampleObject();
int result = sampleObject.DoSomething();
return 0;
}
If I comment out the call to DoSomething(), the program compiles. But with that line in, the compiler complains that left of .DoSomething() must be a class/struct/union.
What do I have to do to get this program and library to play happily together?
I'm writing a mixed mode C++/CLI assembly bridge in order to be able to call into my .NET class library from old C++ application.
In one of my classes in the .NET library one can attach to an event whenever some message needs to be displayed (to console or whatever depending on calling application).
class NetApi
{
public event EventHandler<MessageEventArgs> MessageReported;
}
To call this from native C++ application, I defined the following pointer/delegate bridge:
typedef void(*MessageHandler)(const char* msg);
delegate void ManagedMessageHandler([MarshalAs(UnmanagedType::LPStr)] String^ msg);
Omitting from glue for connecting everything (attaching to MessageReported, removing sender from EventHandler, etc...), here is how I create managed delegate from native function pointer:
class NetApiBridge
{
public:
void SetMessageHandler(MessageHandler handler)
{
wrappedListener = (ManagedMessageHandler^)Marshal::GetDelegateForFunctionPointer((IntPtr)handler, ManagedMessageHandler::typeid);
}
private:
msclr::auto_gcroot<NetApi^ > wrappedApi;
msclr::auto_gcroot<ManagedMessageHandler^ > wrappedListener;
// In another helper ref class in fact, but here pseudo code to simplify
void onMessageReported(Object^ sender, MessageEventArgs^ e)
{
if (!wrappedListener) { return; }
wrappedListenter(e->Message); // Send message to native function pointer
}
}
And I'm almost there when creating dummy C++ test code:
void messageHandler(const char* s)
{
cout << s;
}
void main()
{
NetApiBridge api = new NetApiBridge();
api->SetMessageHandler(&messageHandler);
api->Measure();
delete api;
}
Everything goes fine, events are reported correctly except .... except I receive a PInvokeStackImbalance from Managed Debugging Assistant when leaving the native handler and I clearly don't know why ?
What's wrong with marshaling const char* as UnmanagedType::LPStr here with GetDelegateForFunctionPointer ?
NB: C++ bridge is compiled in x86 if it is important to know here.
typedef void(*MessageHandler)(const char* msg);
delegate void ManagedMessageHandler([MarshalAs(UnmanagedType::LPStr)] String^ msg);
Your delegate declaration is not compatible with the function pointer declaration in 32-bit code. The default calling convention in native code is almost always __cdecl. The default for delegates is __stdcall. A somewhat quirky choice but inspired because interop was assumed to be useful to make OS calls, Windows and COM use __stdcall.
The mismatch right now causes the delegate stub to pop the arguments off the stack. So does the native code so the stack gets imbalanced by 4 bytes. The MDA is there to help you diagnose this common mishap.
You'll have to help and get them to agree. Either with the delegate declaration:
using namespace System::Runtime::InteropServices;
...
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
delegate void ManagedMessageHandler(String^ msg);
Or the function pointer declaration:
typedef void (__stdcall * MessageHandler)(const char* msg);
I wish to call C++ function (here Score()) which is present in Score_Update1.dll.
Both C# & C++ files get compiled successfully. I have also put above dll into the Debug/bin of C# project. But when I run C# code it gives EntryPointNotFoundException.
What could be the reason behind this Exception?
I tried dependency walker for Score_Update1.dll. But it doesn't show any Entry Point
I wish to use PInvoke technique for calling C++ function from C#
// Score_Update1.h
#pragma once
#include <iostream>
using namespace std;
using namespace System;
extern "C"{
#define MYAPI __declspec(dllexport)
namespace Score_Update1 {
public class MYAPI UpdateScore
{
// TODO: Add your methods for this class here.
public:
void Score();
};
}
}
// This is the main Score_Updat1.dll DLL file.
#include "stdafx.h"
#include "Score_Update1.h"
using namespace Score_Update1;
void UpdateScore::Score()
{
cout<<"Score has been updated";
}
C# code is as follows:
using Score_Update1;
using System.Runtime.InteropServices;
namespace GameTesting
{
class Game
{
[DllImport("Score_Update1.dll")]
internal extern static void Score();
static void Main(string[] args)
{
try
{
Game.Score();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}
The reason for EntryPointNotFoundException is that the DLL does not contain an entry point named Score. If you look at the exported names using dumpbin or some similar tool you will see mangled names.
However, using the mangled name isn't going to help you here. You've exported a class and the function you want to call is a member function. You cannot directly instantiate a C++ class from pinvoke. And you cannot call member functions. If you wish to use pinvoke you would need to flatten the class to a C style interface. Another route would be to compile the C++ code to a mixed mode C++/CLI assembly and consume that.
I am trying to call a member function from a C++/CLI assembly from another one, but when I start using DirectX struct I get C3767 error : candidate function not accessib
from Utilities.dll
#pragma once
#include "define.h"
namespace Utilities
{
public ref class Data
{
public:
BOOL CreateBuffer( LPDIRECT3DDEVICE9 dev)
{
...
return TRUE;
}
{
}
And using it from a renderer
#include "Renderer.h"
namespace SomeNamespace
{
SceneRenderer::SceneRenderer(void)
{
}
void SceneRenderer::Render(LPDIRECT3DDEVICE9 dev)
{
...
m_vbo->CreateBuffer(dev); //error C3767: 'Utilities::Data::CreateBuffer': candidate function(s) not accessible
...
}
}
I know that using the address of the device int* (&dev) I can cast back to a LPDIRECT3DDEVICE9, but im looking for a better solution
A managed C++ assembly will not export unmanaged types in its public interface by default. LPDIRECT3DDEVICE9 is an unmanaged type, so your CreateBuffer method will be marked private, regardless of the access specifier provided (kind of stupid that the compiller isn't even generating a warning about this).
Use #pragma make_public or, better yet, do not use unmanaged types in managed interfaces.
Suggestion: Use slimDx or Xna if you want to use DirectX in managed code. These libraries already provide managed wrappers for everything.
I've made very simple wrapper for unmanaged C++ library (to be used with C#). Wrapper has one unmanaged class and one managed class. Managed class has private member that is of unmanaged class and uses it like that.
I've done very simple setup - I've created wrapper for only one function to see if everything is working. But as soon as I create an instance of wrapper, my application get's exception "LoaderLock was detected" with following message:
DLL 'c:\path\CPPWrapper.dll' is
attempting managed execution inside OS Loader lock. Do not attempt to
run managed code inside a DllMain or image initialization function
since doing so can cause the application to hang.
If I turn off breaking for "LoaderLock" exception, I get "FileLoadException was unhandled":
Could not load file or assembly 'CPPWrapper.dll' or one of its dependencies. Exception from HRESULT: 0xE0434352
Any idea what I am doing wrong and how can I fix this problem?
CPPWrapper.h
// CPPWrapper.h
#pragma once
#include "Native.h"
using namespace System;
namespace CPPWrapper {
public ref class Class1
{
public:
Class1() : mnt(new Native)
{
}
~Class1(void)
{
// call the finalize method
this->!Class1();
}
// Finalize (for garbage collection)
!Class1(void)
{
// Remove unmanaged class
delete mnt;
mnt = NULL;
}
void Napravi()
{
mnt->CreatePK();
}
private:
Native *mnt;
};
}
I found that the correct way to fix this is by adding #pragma unmanaged in the dllmain.c Don't turn off breaking for "LoaderLock" exception.
See Initialization of Mixed Assemblies and scroll down to the DllMain section for details. Basically what is happening is that the project is compiling the DllMain function as managed (MSIL) but it only runs in unmanaged code. This #pragma unmanaged forces the function to be compiled as an unmanaged function.
So my dllmain.c is now:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#pragma unmanaged
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;
}
Another potential cause for LoaderLock is initialization of global static objects. In my case, I was compiling a boost::xpressive regex globally and it didn't like doing that when my C++/CLI wrapper was initializing DllMain. I'm not sure why, because it shouldn't have been managed code, but moving it to a function static object fixed it.