Using Directx members between c++\CLI assemblies C3767 - c++-cli

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.

Related

How to convert an existing customized SwapChainPanel from C++/CX to C++/WinRT

I'm attempting to convert my existing C++/CX code to C++/WinRT in order to figure out whether that would enable me to compile that code using Clang. However, I'm stuck early on.
The C++/CX code that I need to convert is used to build a Direct3D component (based on SwapChainPanel) that is eventually utilized in a Windows UWP app that is written in C#. The problem I'm facing is that I just don't manage to convert my customized SwapChainPanel to C++/WinRT.
The code looks as follows:
namespace Why::Does::This::Not::Work
{
[Windows::Foundation::Metadata::WebHostHidden]
public ref class BaseView : public Windows::UI::Xaml::Controls::SwapChainPanel
{
protected private:
BaseView();
// Lots of other stuff
};
}
namespace Why::Does::This::Not::Work
{
[Windows::Foundation::Metadata::WebHostHidden]
public ref class CustomView sealed : public BaseView
{
public:
CustomView();
// ...
event AnimationEventHandler^ AnimationStarted;
private protected:
// Lots of private protected stuff
};
}
namespace Why::Does::This::Not::Work
{
[Windows::Foundation::Metadata::WebHostHidden]
public ref class AnimationEventArgs sealed
{
public:
AnimationEventArgs() {}
AnimationEventArgs(int start, int end)
{
Start = start;
End = end;
}
property int Start;
property int End;
};
[Windows::Foundation::Metadata::WebHostHidden]
public delegate void AnimationEventHandler(Platform::Object^ sender, AnimationEventArgs^ e);
}
As far as I'm able to interpret the documentation I need to do what is described under If you're authoring a runtime class to be referenced in your XAML UI in the documentation.
So, it seems to me that I'd need to author an IDL file in order to generate the COM stuff that is required. However, I cannot even make the skeleton IDL compile:
namespace Why
{
namespace Does
{
namespace This
{
namespace Not
{
namespace Work
{
runtimeclass CustomView : Windows::UI::Xaml::Controls::SwapChainPanel
{
CustomView();
}
}
}
}
}
}
When attempting to compile the above code all I'm getting is
error MIDL2025: [msg]syntax error [context]: expecting { near ":"
error MIDL2026: [msg]cannot recover from earlier syntax errors; aborting compilation
I apologize if you view this as a stupid question. I have read the corresponding documentation but I just fail to comprehend what is really going on when utilizing C++/WinRT. I have plenty of experience with C++ but zero with COM which means it is everything else than straight forward to understand C++/WinRT.
If someone can lend me a hand translating the above C++/CX code to C++/WinRT that would be highly appreciated. Please don't just point me to the documentation, that just doesn't help.
EDIT:
Modifying the sample IDL code as follows successfully compiled it:
namespace Why
{
namespace Does
{
namespace This
{
namespace Not
{
namespace Work
{
[default_interface]
runtimeclass CustomView : Windows.UI.Xaml.Controls.SwapChainPanel
{
CustomView();
}
}
}
}
}
}
However, exposing a user control to another language, in my case C#, such as the one inheriting from SwapChainPanel is dramatically more complex than doing the same thing in C++/CX. There's an IDL to deal with that is not easy to handle because there don't seem to be any complex samples around. That IDL generates several header files that I'm not really sure about what to do with because the documentation is lacking and samples are sparse. C++/WinRT is not for the faint-hearted and its complexity compared to C++/CX is simpy much higher.
It seems to me that to really understand C++/WinRT it is a necessity to have a good grasp of COM because compared to C++/CX, C++/WinRT does a poor job of hiding those COM related internals. This is especially the case when dealing with DirectX. Add to this an IDL that in itself is hard to deal with and a documentation of it that might suffice to get simple samples up and running but does not help much when porting a full fledged C++/CX app.
Doing what we do with C++/CX in C++/WinRT is just not economical for and we will stay on C++/CX until C++/WinRT becomes much more user friendly. Eliminating the need for the IDL (see https://wpdev.uservoice.com/forums/110705-universal-windows-platform/suggestions/36095386-get-rid-of-idl-for-c-winrt-components) would help too.
Without the prospect of being able to compile our code using Clang I would not even think about moving away from C++/CX. Microsoft shouldn't wonder that the adoption of C++/WinRT is slow. If they seriously want to change that they have to lower the entry barrier considerably.
Fully qualified type names in IDL use the period (.) as the namespace separator. A working IDL file would look like this:
namespace Why
{
namespace Does
{
namespace This
{
namespace Not
{
namespace Work
{
runtimeclass CustomView : Windows.UI.Xaml.Controls.SwapChainPanel
{
CustomView();
}
}
}
}
}
}
There's fairly complete documentation at Microsoft Interface Definition Language 3.0 reference. Even with that, it's often challenging to make any sense out of MIDL error messages.

Use native function pointer for listening to managed event / marshaling issue

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);

EntryPointNotFoundException occurred while calling C++ function from C#

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.

C++/CLI wrapper not working (LoaderLock exception)

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.

C++ CLI error C3767: candidate function(s) not accessible

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.