I have a class SaveSystem which contains 2 extern methods: SaveExtern, LoadExtern these methods are supposed to be loaded externally from a lib in order to maintain cloud progress saving. But after this, Unity started to throw these errors on build. What may be the cause and how can I fix it.
Error
Library\Bee\\artifacts\WebGL\build\debug_WebGL_wasm\build.js: undefined symbol:
LoadExtern (referenced by top-level compiled C/C++ code)
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
Code
[DllImport("__Internal")]
private static extern void SaveExtern(string data);
[DllImport("__Internal")]
private static extern void LoadExtern();
I tried reinstalling Unity, deleting everything from \Library, including #if UNITY_WEBGL and #if !UNITY_EDITOR && UNITY_WEBGL
The answer was rather simple:
You need to create a file anyname.jslib in folder /Plugins in your /Assets and implement methods you need inside this file.
You may find info about it here.
https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html
Big thanks to derHugo for making up my mind
Related
Here's the scenario I am confronted with:
in a simple DLL, written in C, there are functions which access files, for example:
DLL_EXPORT void Virt_Hello(void) {
FILE *f = fopen("Hello_world", "w");
if (f) {
fprintf(f, "Hello world!\n");
}
fclose(f);
}
in the managed code:
[SuppressUnmanagedCodeSecurity]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void Virt_HelloDelegate();
private IntPtr m_helloPtr;
m_helloPtr = GetProcAddress(m_libraryPtr, "Virt_Hello");
Virt_Hello = Virt_HelloDelegate)Marshal.GetDelegateForFunctionPointer(m_helloPtr, typeof(Virt_HelloDelegate));
and later, this function is called as:
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public void Hello()
{
Virt_Hello();
}
I've been reading for the last couple of days pretty much everything I could find on this topic however it still doesn't work: the file is not open, and the calling managed code/process just hangs - no exceptions are thrown either.
Tried StdCall calling convention, changed several parameters on the SecurityPermission attribute - to no avail. I've even made sure all assembly dependencies are signed.
Of course I would prefer to integrate it through C++/CLI instead of PInvoke-ing however the DLL is a blackbox for me.
Any help or suggestion how to go forward would be much appreciated.
I'm pretty sure I'm missing something obvious but right now I just can't see it.
My best regards to the community!
I’ve compiled libsass 3.3.6 into a DLL with VS 2015 using the included solution files. Running the code below causes the program to crash immediately with no output.
using System;
using System.Runtime.InteropServices;
namespace Sass.Cli {
static class Sass {
[DllImport(#"C:\...\libsass\win\bin\libsass.dll")]
public static extern String libsass_version();
}
class Program {
static void Main(string[] args) {
Console.WriteLine(Sass.libsass_version());
}
}
}
The source for the invoked function is at sass.cpp:61.
const char* ADDCALL libsass_version(void)
Both the DLL and the above code were compiled for x86. Running the VS debugger on crash gives me the following exception: Unhandled exception at 0x771A9841 (ntdll.dll) in Sass.Cli.exe: 0xC0000374: A heap has been corrupted (parameters: 0x771DC8D0).
Is this something that can be fixed or that I’ve overlooked? Or is it just the case that libsass DLLs aren’t currently working?
When a string is used as a return type then the framework assumes it was allocated by calling CoTaskMemAlloc. It then copies the content of the string and deallocation by calling CoTaskMemFree. That is the explanation for your error.
Solve it by changing the return value to IntPtr and getting the string content with Marshal.PtrToStringAnsi. You won't need to deal located anything since this version string will be static.
I can't tell what the calling convention is. You should check the code and docs to find out. Still, this function is so simple that it behaves the same way for both cdecl and stdcall so that can't explain the error. Still, you will need to get it right for the rest of the library.
Note that I am guessing a little here. You've not provided full details. You should consult the code and docs to double check my guesswork.
In my c# code I need to call a c++ function (myWrapper) that is exported by a dll that I've created.
When myWrapper returns I get the following runtime error:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
As I will show below, I already specified the calling conventions a __cdecl.
In detail, my C# code:
class myClass
{
[DllImport("MyWrapper.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void myWrapper();
public void myMethod()
{
myWrapper();
}
}
c++ code for myWrapper:
#include "IpIpoptApplication.hpp"
extern "C" __declspec(dllexport) void (__cdecl myWrapper)()
{
SmartPtr<IpoptApplication> solver = IpoptApplicationFactory();
ApplicationReturnStatus status = solver->Initialize();
}
The IpoptAppliationFactory function is imported from an external dll in IpOptApplication.hpp (which is part of an open source project and can be viewed from https://projects.coin-or.org/svn/Ipopt/stable/3.11/Ipopt/src/Interfaces/IpIpoptApplication.hpp) with this line:
extern "C" __declspec(dllexport) class Ipopt::IpoptApplication * __cdecl IpoptApplicationFactory();
The strange thing is that the error happens only when "solver->Initialize()" in myWrapper is called. If I comment the call to this method myWrapper returns without errors.
The problem is not related to the definition of "Ipopt::IpoptApplication", nor in the implementation of IpoptApplicationFactory() or Initialize() because 1) they are from a well known open source project (http://www.coin-or.org/projects/Ipopt.xml) used by thousands of programmers, 2) myWrapper works correctly if used in a standalone executable written in c++ code.
I've already googled for hours and I believe that the problem is in the way I call myWrapper but I can't find a solution.
Can anyone give me some suggestion? Thanks a lot.
Roberto
Thanks to Hans Passant the problem has been solved. I must compile "myWrapper" in release mode.
IPOPT DLLS CAN BE COMPILED ONLY IN RELEASE MODE (see readme.txt distributed with IpOpt dlls)! I've set the configuration manager to compile this project always in release mode (even when the solution is in debug).
To debug my myWrapper function (which calls IpOpt dlls), it's necessary to set in the properties of my StartUp project, the check box "Enable unmanaged code debugging"
Since unmanaged code debugging does not allow code modifications during debug, I keep diabled this if I don't need to debug myWrapper.
I hope this will help
Library liba defines a certain function f. When writing a C program that uses function f, compilation will not complete unless I add -lb to the compilation command, even though I don't refer to anything from libb directly in my C code. Using p/invoke, however, I don't have the option of linking to library b and when I call function f (after a [DllImport("liba")], of course) from within my C# code I get a symbol lookup error: /usr/lib/liba.so: undefined symbol: X (X is defined within libb). ldd /usr/lib/liba.so does not contain a row referring to libb. libb is in /usr/lib. I believe this question is essentially the same as Linux, Mono, shared libs and unresolved symbols, but unlike in that case I cannot recompile liba. Is there any way to resolve this problem?
You can also DllImport a function from libb before reaching the code that p/invokes from liba: this will cause libb to be loaded in the process as well.
This is a poor solution, but it might be the best possible under the circumstances: running the resulting mono binary with
LD_PRELOAD=libb.so ./binary.exe
avoids the problem.
Found a good general solution, exemplified in the code below:
class MainClass
{
//Constants from /usr/include/bits/dlfcn.h
private const int RTLD_LAZY = 0x00001; //Only resolve symbols as needed
private const int RTLD_GLOBAL = 0x00100; //Make symbols available to libraries loaded later
[DllImport("dl")]
private static extern IntPtr dlopen (string file, int mode);
[DllImport("a")]
private static extern void f ();
public static void Main (string[] args)
{
//Load libb. RTLD_LAZY could be replaced with RTLD_NOW, but
//RTLD_GLOBAL is essential
dlopen("libb.so", RTLD_LAZY|RTLD_GLOBAL);
//Call f(), no unresolved symbol problem!
f();
}
}
I have been tasked with maintaining a legacy unmanaged c++ system. I do not have access to the source of the entire system but I do have the source to a number of extension dlls that, when included in the same directory as the core system, will be loaded instead of the built in defaults.
I have used the extensions in the past for small changes without problems. My issue now, however, is that I'm being asked to overhaul one of the extension dlls with a substantial amount of extra functionality. Creating this extra functionality in C# is going to be significantly faster (time-to-develop) and more maintainable (our team is primarily composed of C# devs).
The extension dll only has two functions that get called by the core system. The two functions take a bool, int, uint, RECT, Point, CString and return void. Some of the parameters they accept are const.
I'm really keen to find a solid way to bridge these extension functions to C# (.NET 4). So far I've put considerable effort into researching COM Visible, Regasm, c++ mixed mode and interop wrapping libraries. I've also lost a considerable amount of time on proof of concept projects during this research and so far I do not have a working 'bridge'.
What is the most pain free method to get this up and running?
I'm under considerably more pressure on this project than normal - I'm literally starting the C# now and assuming I will get this working somehow.
Really appreciate help and feedback.
Here is the .h and .def files:
modeldll.h
#ifndef INC_MODELDLL_H
#define INC_MODELDLL_H
#ifdef MODELDLL_EXPORTS
#define MODELDLL_API __declspec(dllexport)
#else
#define MODELDLL_API __declspec(dllimport)
#endif
typedef int (*model_updatemodel_t)(const bool update_model, const HWND hwnd, const RECT rect, const POINT next_point, const CString title);
MODELDLL_API int UpdateModel(const bool update_model, const HWND hwnd, const RECT rect, const POINT next_point, const CString title);
typedef int (*model_updatemodelpoint_t)(const bool update_model, const HWND hwnd, const RECT rect, UINT update, const POINT next_point);
MODELDLL_API int UpdateModelPoint(const bool update_model, const HWND hwnd, const RECT rect, UINT update, const POINT next_point);
typedef void (*model_process_message_t)(const char *message, const void *param);
MODELDLL_API void ProcessMessage(const char *message, const void *param);
#endif // INC_MODELDLL_H
modeldll.def:
LIBRARY model.dll
EXPORTS
ProcessMessage #1
UpdateModel #2
UpdateModelPoint #3
I've investigated this topic couple of years ago: I want to use log4net and Npgsql libraries from native code that compiles even withour /clr key.
The main idea behind this technique described by Paul DiLascia in his two remarkable articles:
Managed Code in Visual Studio 2005
Use Our ManWrap Library to Get the Best of .NET in Native C++ Code
For example, here some code snippets that uses log4net library from native code (this code resides in simple non-managed dll, but you should compile this with /clr, but it's not nessary to compile with /clr key code that would use this dll from native code):
// Log4NetWrapper.h
#pragma once
using namespace System;
//facade for log4net library (you may create something like this too)
ref class Log4NetWrapper
{
public:
//I intentionally remove additional methods, because
//I'm trying to show the main principle
static void ReportDebugMessage(char* msg);
private:
static property log4net::ILog^ Logger
{
log4net::ILog^ get();
}
static Object^ syncObject_ = gcnew Object();
static String^ loggerName_ = "";
};
//C-interface that could be accessed from native code
extern "C"
{
_declspec(dllexport) void ReportDebugMessage(char* msg)
{
Log4NetWrapper::ReportDebugMessage(msg);
}
}
// This is the main DLL file.
#include "stdafx.h"
#include "Log4NetWrapper.h"
void Log4NetWrapper::ReportDebugMessage(char* msg)
{
String^ data = gcnew String(msg);
Logger->Debug(data);
}
log4net::ILog^ Log4NetWrapper::Logger::get()
{
if ( loggerName_ == nullptr )
return log4net::LogManager::GetLogger("");
return log4net::LogManager::GetLogger(loggerName_);
}
Compile this code as native dll, than add this dll to your native project, add something like this to that project:
#pragma once
#pragma comment(lib, "Log4NetWrapper")
extern "C"
{
_declspec(dllimport) void ReportDebugMessage(char* msg);
}
And use ReportDebugMessage to access managed code from native code.
Without further information there's not much to go on but I would suggest that you have the following.
Extension Dll (unmanaged code) -> Managed C++ (wrapper) -> C# dll
The first jump is explained in this example:
http://www.codeproject.com/KB/mcpp/cpptomancpp.aspx
You can then load the c# assembly from the managed c++ fairly easily using
using namespace YourNameSpace; // the namespace of the c# routines
In time you may be able to merge the first two.
As Preet suggested, this can be done using a Managed C++ wrapper that will do the bridging you need.
This article explains the entire process:
http://www.codeproject.com/KB/mcpp/unmanaged_to_managed.aspx
I've actually done these sort of things quite a lot several years ago, and all direction work pretty well - C# calling C++ code, C++ code calling C# (via a Managed C++ proxy) and C# passing delegate to a C++ code treating them as function pointers and calling them. I've had some example projects for this, I'll try and find them.