How to load a VC++ CLR library in MFC application? - c++

HI I have a application developed in VC++6.0 ,now I want use some new features from .NET and developed a library, to develop this library I have to use the CLR-VC++ now I packaged this in a DLL.Now I need to call the routine of this DLL in my MFC application.
I tried to write a small MFC application to load this DLL, All the time the LoadLibrary() call is failing #err =126, module not found.I check the the dll with dependency walker everthig is fine there. Please Help me in this regard.
If possible provide me a sample code or link.
Thanks in advance
-Sachin

Use ClrCreateManagedInstance to create a COM-Callable-Wrapper for the object you want to call. Then use it like any other COM type.

you have to go to property page -> Common properties ->Add New reference and include you
CLR Address there .

I have a native C++ application which uses a managed C++ assembly and loads it with LoadLibrary() without problems. I had to do two things, however, before LoadLibrary() worked:
Make sure that the current directory is the one where the managed assembly resides (use chdir() to change directory)
In the managed assembly, the first function invoked by native code only defines the handler for AppDomain::CurrentDomain->AssemblyResolve event which explicitly loads assemblies from the folder of the managed application. It then invokes another managed function to do the rest of the initialization.
The reason for the last point is that CLR attempts to load an assembly dependency only if a function uses it. So I had to ensure that types in non-system assemblies are not referenced before the AssemblyResolve handler has been defined.
ref class AssemblyResolver
{
public:
/// The path where the assemblies are searched
property String^ Path
{
String^ get()
{ return path_; }
}
explicit AssemblyResolver(String^ path)
: path_(path)
{ /* Void */ }
Assembly^ ResolveHandler(Object^ sender, ResolveEventArgs^ args)
{
// The name passed here contains other information as well
String^ dll_name = args->Name->Substring(0, args->Name->IndexOf(','));
String^ path = System::IO::Path::Combine(path_, dll_name+".dll");
if ( File::Exists(path) )
return Assembly::LoadFile(path);
return nullptr;
}
private:
String^ path_;
};
extern "C" __declspec(dllexport) void Initialize()
{
String^ path = "The path where the managed code resides";
AssemblyResolver^ resolver = gcnew AssemblyResolver(path);
AppDomain::CurrentDomain->AssemblyResolve += gcnew ResolveEventHandler(
resolver,
&AssemblyResolver::ResolveHandler
);
FunctionWhichUsesOtherManagedTypes();
}

Related

C++ XE 5 Application and C++ Builder 5 dll compatibility

I have BCB5 dll with method:
extern "C" void __declspec(dllexport) __stdcall SM(TDataSource *DS) {
TForm *form = new TForm(Application);
form->Width = 300;
form->Height = 300;
form->Name = "frm";
TDBGrid *grd = new TDBGrid(form);
grd->Parent = form;
grd->Name = "grd";
grd->Align = alClient;
grd->DataSource = DS;
form->ShowModal();
}
When I call this method from C++ builder 5 application, it's working fine.
try {
typedef void __declspec(dllexport) __stdcall SM(TDataSource *DS);
SM *Upload;
HINSTANCE hDll = LoadLibrary("main.dll");
Upload = (SM*) GetProcAddress(hDll,"SM");
Upload(DataSource1);
FreeLibrary(hDll);
}
catch (Exception *ex) {
ShowMessage(ex->Message);
}
But, if I'm trying to call this method from C++ XE 5 application, I get Access Violation.
Is there a way to solve the problem of data transmission from XE 5 application to BCB 5 dll without recompile dll in XE5?
It is not safe to pass/use RTL/VCL objects over the DLL boundary like you are doing, unless both EXE and DLL are compiled with Runtime Packages enabled so that they share a common instance of the same RTL and VCL frameworks (but then you have to deploy the RTL/VCL BPL binaries with your app).
Your DLL doesn't work in XE5 because the DLL is expecting the BCB5 version of the TDataSource component, not the XE5 version. No, they are not compatible, as they have different memory layouts and dependancies.
So your choices are to either:
recompile the DLL in XE5, and live with the risk that passing TDataSource over the DLL boundary is not safe in general, unless you enable Runtime Packages.
re-write the DLL to be a Runtime Package (BPL) instead. Then passing TDataSource between EXE and DLL is safe. However, Runtime Packages are version-specific, so you will need to compile separate BPLs if you need to continue using the code in both BCB5 and XE5.
re-write the DLL to not pass a TDataSource over the DLL boundary to begin with. Figure out another interop-safe way to exchange data between EXE and DLL.

Access violation using a C++ function from a DLL

I have a game engine written in C++ which I'm porting to Windows (from Mac). It uses C++11 and OpenGL, and for all intents and purposes, it runs!
I'm using a DLL for my game engine which is linked implicitly to the game .exe at runtime. The problem is, when I try to use a utility class from the DLL, FileSystem, to find a resource file (a texture, but I don't think it's important), I get this error:
First-chance exception at 0x00007FF9CF988830 (PocoFoundation64.dll) in TestEquinox.exe: 0xC0000005: Access violation reading location 0x000000136A4FF000.
The problem comes when I call this method of my FileSystem class from the DLL (it's designed to take a filename/partial path and it looks in various places to find the full path):
Poco::Path FileSystem::Get(const std::string &filename) {
std::vector<Poco::Path> paths = {
filename,
ResourceFolder() / filename //<<<<< ERROR HERE
};
for (const Poco::Path &path : paths) {
try {
if (Poco::File(path).exists()) {
return path;
}
} catch (...) { }
}
Logger("FileSystem", std::cerr) << "Could not find file '" << filename << "'!";
return {};
}
Visual Studio shows the error as being at the call of ResourceFolder(), another method from the same class, also in the DLL. This appears so:
Poco::Path FileSystem::ResourceFolder() {
Poco::Path userData;
//--SNIP-- (other OS's #ifdef'd here)
// GAME->StartupPath is a std::string containing the exe's parent folder
userData = (Poco::Path(GAME->StartupPath).parent() / "Resources").makeDirectory();
//--SNIP-- (and here)
try {
if (!Poco::File(userData).exists()) {
Poco::File(userData).createDirectories();
}
} catch (...) {}
return userData;
}
From the looks of it, it's to do with Poco's data types not being instantiated properly? I've built it from source with all the same compiler settings (64-bit, multi-byte character set, VS2013), so I don't see how it could be a name mangling/data layout issue.
One more thing to note - I copied the entire FileSystem class from the DLL to a class local to my game project, called FileSystem2. Calling FileSystem2::Get with the same parameters worked correctly and without crashing, despite being the same code.
Hoping someone can point me in the right direction?!
Usually errors like this stem from using incompatible runtime libraries that your module uses. Please check the following for all of your modules in the Visual Studio properties:
Project Properties -> C/C++ -> Code Generation -> Runtime Library.
The runtime setting (Multithread DLL, Multithread Debug DLL, etc.) must match up with all the modules you're compiling. If they do not match, choose one runtime, and rebuild all of your modules using that runtime.

Why does WP8.1 runtime component throw C++ exception on call to boost::filesystem::file_size()?

Windows Phone 8.x developers porting C++ with Boost code to WP8.x are aware that several Boost binary libraries contain banned Win32 calls. Thus, these Boost libraries need to be ported to WP8.x.
Steven Gates, a Microsoft engineer, ported several Boost libraries (i.e., system, chrono, date_time, smart_ptr, signals2, and thread) and wrote an excellent blog describing how he did it.
One critical Boost library he did not port is filesystem. Although I am new to WinRT and runtime components, I want to attempt to port this library to Windows Phone 8.1 (WP8.1 has less banned functionality than WP8.0, and does not require RPAL ["restricted platform allow list"] for many functions).
I began by commenting out all filesystem source code that does not compile under Windows Phone 8.1, reaching a state where I could build the filesystem library for WP8.1 ARM using the following Boost b2 command:
b2 toolset=msvc-12.0 windows-api=phone link=static architecture=arm filesystem
My overall plan is to implement the commented-out functions one at a time, testing the ported code through a minimal WP 8.1 app.
My next step was to write a minimal Windows Phone 8.1 app together with a Windows Phone Runtime Component 8.1 project, both bundled in a single solution (the runtime component will interface with the Boost library). To get them working I:
added the runtime component as a reference to the main app project
linked the Boost filesystem static library to the runtime component
added an API function within the runtime component called GetFileSize() that the app can invoke. The purpose is to exercise the boost::filesystem::file_size() function within the ported Boost library.
linked code to a UI button that, when pressed, calls into the runtime component to invoke the GetFileSize() function
The problem I have is that the call to boost::filesystem::file_size() throws an exception, and it is not obvious what the problem is.
Here is the relevant code I've written.
namespace MinimalWindowsRuntimeApp
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
private void GetFileSize_Click(object sender, RoutedEventArgs e)
{
String filepath = "\\Phone\\Pictures\\Camera Roll\\WP_20140106_001.jpg";
var newObject = new WindowsRuntimeComponent1.Class1();
newObject.GetFileSize(filepath);
}
}
}
When I press the dedicated button on the Windows Phone screen it invokes the GetFileSize_Click() function. This code creates an instance of the WindowsRuntimeComponent1.Class1() activatable class and calls its GetFileSize () function:
// Class1.cpp
#include "pch.h"
#include "Class1.h"
#include "boost/filesystem.hpp"
using namespace WindowsRuntimeComponent1;
using namespace Platform;
Class1::Class1()
{
}
int64 Class1::GetFileSize(Platform::String ^filepath)
{
boost::filesystem::path p (filepath->Data ());
__int64 filesize = (__int64) boost::filesystem::file_size (p);
return filesize;
}
The intention is for the GetFileSize() function in the runtime component to instantiate a boost::filesystem::path object (which takes a wide-char string of the path) and invoke the boost::filesystem::file_size() function.
The problem is that the call to file_size() throws an exception, as shown in the output window:
First-chance exception at 0x774E59A3 in MinimalWindowsRuntimeApp.exe: Microsoft C++ exception: boost::filesystem::filesystem_error at memory location 0x0315E498.
Tracing into Boost with the native debugger shows the code in Boost's operations.cpp that fails:
BOOST_FILESYSTEM_DECL
boost::uintmax_t file_size(const path& p, error_code* ec)
{
. . .
# else // Windows
// assume uintmax_t is 64-bits on all Windows compilers
WIN32_FILE_ATTRIBUTE_DATA fad;
if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0,
p, ec, "boost::filesystem::file_size"))
return static_cast<boost::uintmax_t>(-1);
. . .
# endif
}
The failure occurs while calling the Win32 API GetFileAttributesExW() function. At the point of invocation, p.c_str() equals the expected "\Phone\Pictures\Camera Roll\WP_20140106_001.jpg". The function, which is supported for Windows Phone 8.1, fails and returns 0, which causes Boost's error() function to throw an exception.
My two questions are:
Why is the Win32 API GetFileAttributesExW function failing?
Is the Windows Phone file path I pass to GetFileSize (i.e., "\Phone\Pictures\Camera Roll\WP_20140106_001.jpg") the valid way to specify a file on the Windows Phone?
Many thanks in advance for any help you can give.
You need to include the drive letter ("C:\\path\\to\\file") when creating paths on Windows. Note that in a real Windows Phone app you should never hard-code the path because the user can move stuff to the SD card. You should also never store the absolute path to a file for the same reason. It's OK for your test though.
Also, you're trying to read from the Camera Roll, which you can't do directly (you can only read protected files like that through WinRT APIs). But here is a sample showing it working (replace App::App from a new, blank C++ Windows Phone project):
App::App()
{
InitializeComponent();
Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending);
auto path = std::wstring(Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data()) + L"\\Assets\\SplashScreen.scale-240.png";
std::wstringstream ss;
ss << L"Path is " << path << std::endl;
WIN32_FILE_ATTRIBUTE_DATA data{};
if (GetFileAttributesExW(path.c_str(), GET_FILEEX_INFO_LEVELS::GetFileExInfoStandard, &data))
{
ss << L"Size is " << (((LONG)data.nFileSizeHigh << sizeof(DWORD)) + (LONG)data.nFileSizeLow) << std::endl;
}
else
{
ss << L"Can't get size info: " << GetLastError() << std::endl;
}
OutputDebugString(ss.str().c_str());
}

What is a good way to get a C++ and WPF app to communicate

I have a C++ dll which is a plug-in to ADOBE Acrobat. It needs to talk often ( to and fro) and with a fair amount of complicated data-structures to a WPF process.
Any thoughts of what might be the best way to go . Need something that is a little long term and maintainable, in other words would love some ideas around something that lets both process make what looks like methods calls and some infrastructure piece does the marshaling and dispatch . I've tried Windows messages but ran into some conflict issues on ADOBE, also not really interested in anything that causes the dll to get adobe to load the CLR. Only other things that come to my mind are named pipes or http.
Thanks in Advance
Named pipes could do but you won't get a feeling of just calling functions. Named pipe are quite low-level IPC. Other IPC options are:
Windows RPC, you definitely get a feeling of just calling functions.
What about hosting a COM object in WPF application and calling it from the Adobe plugin?
I would go with COM:
Implement an interface in WPF app
generate a typelib (e.g by using regasm)
import the typelib into C++ dll
communicate
if you need bidirectional communication, C++ dll can also implement a COM interface which is then accessed from WPF application.
This is what I have used to connect legacy C++ app with new .NET service, and it works great. The biggest issue is to find people who know COM, but fortunately this doesn't require a deep understanding of COM.
your hint with COM is very intersting. I tried to implement this concept.
I have created an interface in my WPF CallDllFromWpf3Interface project:
using System.Runtime.InteropServices;
namespace CallDllFromWpf3Interface
{
[Guid("F6E0E2E8-CCC6-487B-8BF1-261265061E6A")]
public interface SetValueInterface
{
void SetValue(int value);
}
}
Then I have generated the typelib with the regasm tool:
regasm CallDllFromWpf3Interface.exe /tlb
With the "oleview" tool I can see the typelib and the interface.
The next step was to create a c++ dll project called "CallSetValueInterface".
In my CallSetValueInterface.cpp file I wrote this lines:
#import "D:\Thomas\Programming\WPF\Basics\CallDllFromWpf\CallDllFromWpf3Interface\CallDllFromWpf3Interface\bin\Debug\CallDllFromWpf3Interface.tlb"
void
CallSetValueInterface::startAcq(void)
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
CallDllFromWpf3Interface::SetValueInterfacePtr Svip("f6e0e2e8-ccc6-487b-8bf1-261265061e6a");
Svip->SetValue(55);
Svip = NULL;
CoUninitialize();
}
After a successful build of the dll project I copied "CallSetValueInterface.dll" to the "CallDllFromWpf3Interface" project.
Finally I changed my WPF code to:
#region SetValueInterface Members
public void SetValue(int value)
{
MyValue = value;
}
#endregion
[DllImport("CallSetValueInterface.dll", EntryPoint = "startAcq", ExactSpelling = true, SetLastError = true)]
public static extern void StartAcqFromDll();
private void Button_Click(object sender, RoutedEventArgs e)
{
StartAcqFromDll();
}
And when the debugger came to StartAcqFromDll() there occurred an error dialog "An unhandled exception of type 'System.Runtime.InteropServices.SEHException' occurred in CallDllFromWpf3Interface.exe".
Does anybody know whats going wrong?
Regards,
ThomasL.

Tcl Extension Calling a VB.NET DLL

I have a need to create a Tcl extension that calls a managed .NET DLL/Class Library. Currently, the structure of my application is Tcl > DLL Wrapper (C++ CLR) > .NET Class Library (VB.NET), where ">" represents a function call.
My VB.NET DLL just takes a value and returns it back, keeping it simple for now. In the end, this will do some more advanced stuff that makes use of some .NET functionality.
Public Class TestClass
Public Function TestFunction(ByVal param As Integer) As Integer
Return param
End Function
End Class
My Tcl Extension (C++ CLR) creates an object of the type above
int TestCmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
// Check the number of arguments
if (objc != 2) {
Tcl_WrongNumArgs(interp, 0, objv, "arg");
return TCL_ERROR;
}
int param, result;
if (Tcl_GetIntFromObj(interp, objv[1], &param) != TCL_OK)
return TCL_ERROR;
SimpleLibrary::TestClass^ myclass = gcnew SimpleLibrary::TestClass(); //System.IO.FileNotFoundException
result = myclass->TestFunction(param);
Tcl_SetObjResult(interp, Tcl_NewIntObj(result));
return TCL_OK;
}
And finally, my Tcl script loads the extension and calls the function.
load SimpleTclExtension.dll
TestCmd 2
If my VB.NET DLL is in the same directory as my extension DLL, the extension crashes when it instantiates a TestClass object. I've noticed if the VB.NET DLL is relocated to C:\Tcl\bin, the extension will find it, and TestCmd can be called just fine. The problem is that this will eventually need to be deployed across a number of PCs, and it's preferred not to mingle my application's files with another application's.
It seems like there should be some configuration settings that will fix this problem, but I'm not sure where. Any help is greatly appreciated.
Firstly, depending on just what kind of Tcl application you are using you may want to look at Eagle which is a implementation of Tcl in CLR.
I think you are bumping into .Net's desire to only load assemblies from your application's directory or its immediate subdirectories. The application here is the tclsh/wish executable which is why moving the .Net assembly makes it load. This is something you can fix with suitable manifests or calls to the API to permit assembly loading from alternate locations. In this case I think you will need to run some initialization code in your Tcl extension when it gets loaded into the Tcl interpreter to init the CLR and add the extensions location as a suitable place to load assemblies from. It has been a while since I was looking at this so I forgot the details but I think you want to look at the AppDomain object and check the assembly loading path properties associated with that or its child objects. Try AppDomain.RelativeSearchPath
To be more specific, Eagle includes Garuda which is a Tcl extension built specifically to allow calling .Net from Tcl