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.
Related
I have a C++ CLR/CLI project, I wonder how to embed a localized satellite dll into my exe application, I found similar solutions but it's for C# projects which is pretty different from my project structure.
Is it possible to embed it directly into the binary?
By the way I'm getting issues with namespaces, it seems my custom namespace is not linked to my localized resource file.
I've been searching for hours to find a solution for a C++ CLR/CLI project which is pretty different comparing with C# projects which apparently comes with Build Action and Custom Tool Namespace all these options we don't have in a CLR/CLI project, it's really important, especially if we have changed Namespaces so we gotta use Resource Logical Name instead. Here's my answer how to solve Namespace issues, this also works for localized resource files linked to satellite dlls.
After your localized satellite dll is generated, include that in your project as Compiled Managed Resource you can set that by opening its file property and setting the Item Type. In projects such as C# you won't find that but something similar like "Embedded Resource". Anyways this is intended to C++ CLR/CLI projects only. If you have changed namespaces, don't forget to set Resource Logical Name of the respective resource file.
Next step is to do some code in order to embed that dll into our exe application, here's a good one for that:
Since C++ CLR/CLI doesn't support lambda expressions we have to do this way:
private: System::Reflection::Assembly^ currentDomainAssemblyResolve(System::Object^ sender, System::ResolveEventArgs^ args) {
System::Reflection::AssemblyName^ assemblyName = gcnew System::Reflection::AssemblyName(args->Name);
System::String^ resourceName = assemblyName->Name + ".dll";
System::IO::Stream^ stream = System::Reflection::Assembly::GetExecutingAssembly()->GetManifestResourceStream(resourceName);
array<Byte>^ assemblyData = gcnew array<Byte>((unsigned long) stream->Length);
try {
stream->Read(assemblyData, 0, assemblyData->Length);
} finally {
if (stream != nullptr) delete stream;
}
return System::Reflection::Assembly::Load(assemblyData);
}
Usage:
//Put it in your constructor before InitializeComponent()
MyClass(void) {
AppDomain::CurrentDomain->AssemblyResolve += gcnew System::ResolveEventHandler(this, &MyNameSpace::MyClass::currentDomainAssemblyResolve);
InitializeComponent();
}
So now it's no longer necessary satellite dlls to load your localized resources.
Use a free application packer to bundle files into a single exe.
https://enigmaprotector.com/en/aboutvb.html
This one is free, I use it and it works very well for me.
With g++ is there a way to link a library so that all symbols are under a new namespace?
For example, I'd like to use a library in my program which has conflicting symbols with my existing code. Is there a way to encapsulate the linked library under a new name space through the linker, without the need to modify source code?
Edit
Here is some more detail:
I am working on a Qt application, which functions as an "Application Manager" for an embedded device. This application links the Qt module "webkitwidgets", which is a library.
the applications managed by this application manager are built as shared libraries, and when they are launched by this manager program a wrapper programed (Launcher) is forked, the launcher uses QLibrary to load the shared library:
bool ProcessInitImpl::loadLibrary(const QString& libraryPath) {
qTrace() << libraryPath;
QLibrary lib(libraryPath);
lib.setLoadHints(QLibrary::ResolveAllSymbolsHint | QLibrary::ExportExternalSymbolsHint);
if (lib.load()) {
qDebug() << libraryPath << " is loaded successfully!";
typedef void (*RegistrationMethod)();
RegistrationMethod registrationMethodInTheSharedLibrary = (RegistrationMethod) lib.resolve("registerMetaTypes");
if (registrationMethodInTheSharedLibrary) {
registrationMethodInTheSharedLibrary();
return true;
}
}
qCritical() << libraryPath << " failed to load!" << lib.errorString();
return false;
}
the problem is that this launcher is suppose to be decoupled from the manager, using IPC to communicate between the launcher instances and the manager. However, the launcher is linked to the manager, which in turn is linked to webkitwidgets. There is an application which contains conflicting symbols within webkitwidgets.
Given all of that above, the only thing that came to mind for me was modifying the launcher wrapper so that it had no dependencies on the manager and thus didn't link webkitwidgets. I just wanted to see if there was another way to address this before going down that path.
With g++ is there a way to link a library so that all symbols are under a new namespace?
Probably not (namespaces are a C++ thing and are implemented by name mangling), and you don't specify what exactly loading a dynamically linked library means to you and you don't tell anything about the actual conflicts you've got. In reality, it is quite complex. Read Levine's Linkers and Loaders and Drepper's How to Write Shared Libraries for details, and also the documentation of binutils ld, ld-linux(8) etc. Read also about dlmopen(3) (which I never used).
For example, I'd like to use a library in my program which has conflicting symbols with my existing code.
Don't touch the library, or the way you are loading it, but touch your program. It would be much simpler (and you could use tools for that, perhaps code your own GCC plugin or use GCC MELT for that). Perhaps it could be as simple as adding a few namespace and or using in your own C++ source code. YMMV.
Practically speaking, how to approach the problem depends a lot on the actual conflicts you are observing and how much you have ...
I do not think you can do that through linker. You can load library dynamically and manually assign function pointers. For linux this could be done by something like this:
namespace wrapper {
int (*foobar)( int ); // replacing int foobar(int) from lib
};
// initialization code
void *handle = dlopen( "libname", flags );
if( !handle ) ...
foobar = reinterpret_cast<declspec(foobar)>( dlsym( handle, "foobar" ) );
// now calling function
int r = wrapper::foobar( 123 );
Is there an existing way to do it? No, unless there's an API I'm unaware of (that's not unthinkable). You'd need to write a custom loader that does name translation.
It shouldn't be too hard on any open-source OS, where you can just take the existing loader's source code and patch it to do the modifications you need.
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());
}
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], ¶m) != 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
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();
}