[Mono-dev] mono_method_desc_search_in_image problem, and some question...
pierre
pierre.saunier at ppmodeler.com
Wed Feb 21 10:20:03 UTC 2018
Hi,
Anyone about this??
if I run "mono_domain_unload(domain);"
and after do
assembly = mono_assembly_load_from_full(image, referenceName, &status,
FALSE);
it is not working properly if referenceName is kept from one launch to
the next...
I think the code bellow is showing it... or am I doing something wrong??
may be it is linked to the "[DllImport ("__Internal"..." which blocking
the unloading of the assembly?
And a question: Is there a way to debug a running assembly (embeded)?
On python and lua, you can register a function that is called on every
line executed... I totally understand it is different for mono, but what
are my options? where can I find documentations about debugging from and
embedding application?
Thanks,
Pierre
The source to test is (mono_test.c):
/******************************************************************************************************************/
#include <mono/jit/jit.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/threads.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/mono-gc.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/mono-debug.h>
#include <mono/utils/mono-logger.h>
/**********************************************************************************/
/* */
/**********************************************************************************/
#define TRUE 1
#define FALSE 0
#define BYTE unsigned char
#define gMalloc malloc
#define gFree free
BYTE *readFile(FILE *f, size_t *size)
{
BYTE *buffer;
size_t i;
fseek(f, 0, SEEK_END);
*size = ftell(f);
fseek(f, 0, SEEK_SET);
buffer = (BYTE *) gMalloc(*size);
if(buffer == NULL) return NULL;
i = fread(buffer, 1, *size, f);
if(i != *size)
{
gFree(buffer);
return NULL;
}
return buffer;
}
/**********************************************************************************/
/* */
/**********************************************************************************/
static MonoDomain *rootDomain;
static MonoDomain *domain;
static MonoImage *image;
static MonoAssembly *assembly;
/**********************************************************************************/
/* */
/**********************************************************************************/
__declspec(dllexport) void mono_report(char* str)
{
printf("%s\n", str);
}
/**********************************************************************************/
/* */
/**********************************************************************************/
static int monoScriptCompile(char *fileName, char *referenceName)
{
int res;
char *ret, *strErr, *str;
char buffer[256];
FILE *f;
BYTE *data;
size_t dataLen;
MonoImageOpenStatus status;
MonoAssemblyName *aName;
if(domain != NULL)
{
res = mono_domain_set(rootDomain, FALSE);
if(!res)
{
printf("Failed to set root domain\n");
return FALSE;
}
mono_domain_unload(domain);
mono_gc_collect(mono_gc_max_generation());
}
domain = NULL;
image = NULL;
assembly = NULL;
domain = mono_domain_create_appdomain("ScriptSubDomain", NULL);
res = mono_domain_set(domain, FALSE);
if(!res)
{
printf("Failed to set domain\n");
return FALSE;
}
sprintf(buffer, "%s.dll", fileName);
f = fopen(buffer, "rb");
if(f == NULL)
{
printf("Cannot open file: %s\n", buffer);
return FALSE;
}
data = readFile(f, &dataLen);
fclose(f);
// open the assembly from the data we read, so we never lock files
image = mono_image_open_from_data_with_name(data, dataLen,
TRUE /* copy data */,
&status,
FALSE /* ref only */,
referenceName);
gFree(data);
if (status != MONO_IMAGE_OK || image == NULL)
{
printf("Cannot create image from data\n");
return FALSE;
}
// load the assembly
assembly = mono_assembly_load_from_full(image, referenceName,
&status, FALSE);
if (status != MONO_IMAGE_OK || assembly == NULL)
{
printf("failed to load assembly\n");
mono_image_close(image);
return FALSE;
}
aName = mono_assembly_get_name(assembly);
printf("Assembly Name: %s\n", mono_stringify_assembly_name(aName));
res = mono_domain_set(rootDomain, FALSE);
return TRUE;
}
/**********************************************************************************/
/* */
/**********************************************************************************/
static int monoScriptRun(void)
{
int res, base;
char *ret, *strErr;
MonoMethodDesc* monoMethodDesc;
MonoMethod* method;
MonoObject *exception;
if(domain == NULL || assembly == NULL)
{
printf("Run Failed: Not compiled\n");
return FALSE;
}
if (!mono_domain_set(domain, FALSE))
{
printf("Run Failed: set domain failed\n");
return FALSE;
}
monoMethodDesc = mono_method_desc_new("Script:Main", 0);
if(monoMethodDesc == NULL)
{
printf("mono_method_desc_new failed\n" );
return FALSE;
}
//Search the method in the image
method = mono_method_desc_search_in_image(monoMethodDesc, image);
mono_free(monoMethodDesc);
if(method == NULL)
{
printf("mono_method_desc_search_in_image failed\n");
return FALSE;
}
//run the method
exception = NULL;
mono_runtime_invoke(method, NULL, NULL, &exception);
if(exception != NULL)
{
printf("An exception was thrown when calling Script:Main!\n");
return FALSE;
}
res = mono_domain_set(rootDomain, FALSE);
return TRUE;
}
/**********************************************************************************/
/* */
/**********************************************************************************/
static void monoInit(void)
{
if(rootDomain == NULL)
{
mono_set_dirs("C:\\Program Files\\Mono\\lib",
"C:\\Program Files\\Mono\\etc");
rootDomain = mono_jit_init("ScriptEngine");
mono_thread_set_main(mono_thread_current());
}
}
/**********************************************************************************/
/* */
/**********************************************************************************/
int main(int argc, char **argv)
{
mono_report("Starting");
monoInit();
monoScriptCompile("code1", "code.dll");
monoScriptRun();
monoScriptCompile("code2", "code.dll");
monoScriptRun();
monoScriptCompile("code2", "code2.dll");
monoScriptRun();
}
/******************************************************************************************************************/
The cs source (code1.cs) for the first ddl (compiled with mcs code1.cs
-target:library):
/******************************************************************************************************************/
using System;
using System.Runtime.InteropServices;
public class ScriptEngine
{
[DllImport ("__Internal", EntryPoint="mono_report")]
static extern public void report (String str);
}
public class Script
{
static void Main ()
{
ScriptEngine.report("Code 1");
}
}
/******************************************************************************************************************/
The cs source(code2.cs) for the second ddl (compiled with mcs code2.cs
-target:library):
/******************************************************************************************************************/
using System;
using System.Runtime.InteropServices;
public class ScriptEngine
{
[DllImport ("__Internal", EntryPoint="mono_report")]
static extern public void report (String str);
}
public class Script
{
static void Main ()
{
ScriptEngine.report("Code 2");
}
}
/******************************************************************************************************************/
On 13/02/2018 18:22, pierre wrote:
> Here a sample in one (dirty) c file...
> the file can be compiled easily, just adding the mono library and the
> mono include path.
>
> the core is doing:
>
> monoScriptCompile("code1", "code.dll");
> monoScriptRun();
> monoScriptCompile("code2", "code.dll");
> monoScriptRun();
> monoScriptCompile("code2", "code2.dll");
> monoScriptRun();
>
> And the result on my system is:
>
> Starting
> Assembly Name: code1, Version=0.0.0.0, Culture=neutral,
> PublicKeyToken=null
> Code 1
> Assembly Name: code1, Version=0.0.0.0, Culture=neutral,
> PublicKeyToken=null
> *Code 1*
> Assembly Name: code2, Version=0.0.0.0, Culture=neutral,
> PublicKeyToken=null
> Code 2
>
> and as you can see, the code is not reloaded properly when the
> reference is kept, but reloaded in the second case!!!
>
>
> On 13/02/2018 14:15, R Zaghi wrote:
>> Just for the record, I mean write it in a C# class and load that one
>> class so you can handle everything in C# itself - much more robust.
>>
>>
>> On Tue, 13 Feb 2018 at 19:04, R Zaghi <rzaghi at mosaic3dx.com
>> <mailto:rzaghi at mosaic3dx.com>> wrote:
>>
>> If this is actually a problem with a library like mono then it
>> sounds like a caching problem. If you build mono from source then
>> it's easier to look into this...
>>
>> Compare your code with this example. In the example, the .dll
>> assembly is re-loaded in a loop. You can see the clean up portion
>> and the shutdown or initialisation portions too:
>>
>> https://github.com/ramin-zaghi/mono-embedding
>>
>> Regarding how to compile code at runtime without a system() call,
>> you can use CodeDom (look it up) to compile from files, or in a
>> mono-specific way use Mono Compiler Service (e.g the Evaluator
>> and CompilerContext classes - google them) which allow you to
>> evaluate partial expressions/statements/etc.
>>
>> I use both depending on situation and they work pretty well.
>> Roslyn is apparently another option but let's not go there :)
>>
>> R.
>>
>>
>>
>>
>>
>> On Tue, 13 Feb 2018 at 16:17, pierre
>> <pierre.saunier at ppmodeler.com
>> <mailto:pierre.saunier at ppmodeler.com>> wrote:
>>
>> Thanks for the answer.
>>
>>
>> > you 100% sure the old files are all overwritten?
>> Yes, I have checked the file time... and also included a
>>
>> remove(fileName);
>>
>> to be sure!
>>
>>
>> >There are a couple of different ways to get compiled binary
>> at runtime without a system() call
>> Which ones?
>>
>> I have tried something:
>> calling mono_image_open_from_data_with_name and
>> mono_assembly_load_from_full with a different file name on
>> every compile and it is working!!!
>>
>> so, the following code is not reloading properly:
>>
>> monoEngine->fileName = strdup("code.dll");
>>
>>
>> monoEngine->image =
>> mono_image_open_from_data_with_name(data, dataLen,
>> TRUE /* copy data */,
>> &status,
>> FALSE /* ref only */,
>> monoEngine->fileName);
>> if (status != MONO_IMAGE_OK || monoEngine->image == NULL)
>> {
>> }
>> monoEngine->assembly =
>> mono_assembly_load_from_full(monoEngine->image,
>> monoEngine->fileName,
>> &status, FALSE);
>> if (status != MONO_IMAGE_OK || monoEngine->assembly == NULL)
>> {
>> }
>>
>>
>> but, the same with a different file name on every run (only
>> the monoEngine->fileName creation differ) is working:
>>
>> static int version = 1;
>> ...
>>
>> sprintf(monoEngine->fileName, "code%03d.dll", version);
>> version ++;
>>
>>
>> monoEngine->image =
>> mono_image_open_from_data_with_name(data, dataLen,
>> TRUE /* copy data */,
>> &status,
>> FALSE /* ref only */,
>> monoEngine->fileName);
>> if (status != MONO_IMAGE_OK || monoEngine->image == NULL)
>> {
>> }
>> monoEngine->assembly =
>> mono_assembly_load_from_full(monoEngine->image,
>> monoEngine->fileName,
>> &status, FALSE);
>> if (status != MONO_IMAGE_OK || monoEngine->assembly == NULL)
>> {
>> }
>>
>> Is there a wait to be introduced after a mono_domain_unload?
>> It is like doing mono_domain_unload,
>> mono_image_open_from_data_with_name and
>> mono_assembly_load_from_full with the same file name is
>> detected and the unload is not performed....
>>
>>
>> > This is more likely to be a problem outside of mono.
>> I do agree... but I am running out of idea on why!!!
>>
>>
>> and for mono_method_desc_search_in_image? is it bug?
>>
>>
>> Pierre
>>
>>
>> On 13/02/2018 07:15, R Zaghi wrote:
>>> I think we need to know a bit more about what you are doing
>>> in the code exactly but as a quick first guess if you are
>>> recompiling using a system() call then are you 100% sure the
>>> old files are all overwritten? There are a couple of
>>> different ways to get compiled binary at runtime without a
>>> system() call which I prefer but if you are using a system()
>>> call then have you tried two separate calls with two
>>> parallel binaries loaded as a start to debug your code?
>>>
>>> This is more likely to be a problem outside of mono.
>>>
>>> Ramin
>>>
>>>
>>>
>>>
>>> Ramin Zaghi
>>>
>>> *Mosaic3DX™ | User Interface Technology*
>>> St John's Innovation Centre,
>>> Cowley Road,
>>> Cambridge,
>>> CB4 0WS, UK*
>>> *
>>> *E*:**rzaghi at mosaic3dx.com <mailto:rzaghi at mosaic3dx.com>
>>> *T*: +44 1223 421 311 <tel:+44%201223%20421311>
>>> http://linkedin.com/in/raminzaghi
>>>
>>>
>>>
>>> On Tue, 13 Feb 2018 at 01:27, pierre
>>> <pierre.saunier at ppmodeler.com
>>> <mailto:pierre.saunier at ppmodeler.com>> wrote:
>>>
>>> Hi,
>>>
>>> I am trying to embed mono... and I ran into a problem
>>> with the code:
>>>
>>> monoMethodDesc = mono_method_desc_new("Script:Main", 0);
>>> method =
>>> mono_method_desc_search_in_image(monoMethodDesc,
>>> monoEngine->image);
>>>
>>>
>>> It is returning a method on the cs code:
>>>
>>> public class Script
>>> {
>>> static public void Main ()
>>> {
>>> ScriptEngine.report("--Main Called ");
>>> }
>>> }
>>>
>>>
>>> but it is also returning a method on the cs code (with
>>> the wrong class name):
>>>
>>> public class Script*2*
>>> {
>>> static public void Main ()
>>> {
>>> ScriptEngine.report("--Main Called ");
>>> }
>>> }
>>>
>>> while it should only return for:
>>>
>>> monoMethodDesc =
>>> mono_method_desc_new("Script2:Main", 0);
>>>
>>>
>>> Am i doing something wrong or is this a bug? It seem
>>> that mono_method_desc_search_in_image is returning a
>>> value if the actual class name is starting with the
>>> given class name.... so, the same method is returned if
>>> I look for "Script:Main" but the declared class is
>>> "Script:Main", "Script_test:Main" or "Script2:Main"...
>>>
>>> and a question:
>>> is there a way to know if mono_domain_unload was
>>> successful or not?
>>>
>>> I am creating an app domain per script so that I can
>>> recompile and reload the script at will...
>>> I do not detect any error, but the new script seems not
>>> to replace the old one...
>>> Basically, I am doing:
>>>
>>> res = mono_domain_set(rootDomain, FALSE);
>>> mono_domain_unload(monoEngine->domain);
>>> monoEngine->domain =
>>> mono_domain_create_appdomain("ScriptEngine-sub", NULL);
>>>
>>> data = readFile(f, &dataLen);
>>> fclose(f);
>>> monoEngine->image =
>>> mono_image_open_from_data_with_name(data, dataLen,
>>> TRUE /* copy data */,
>>> &status,
>>> FALSE /* ref only */,
>>> monoEngine->fileName);
>>> free(data);
>>> if (status != MONO_IMAGE_OK || monoEngine->image
>>> == NULL)
>>> {
>>> return FALSE;
>>> }
>>>
>>> // load the assembly
>>> monoEngine->assembly =
>>> mono_assembly_load_from_full(monoEngine->image,
>>> monoEngine->fileName,
>>> &status, FALSE);
>>> if (status != MONO_IMAGE_OK ||
>>> monoEngine->assembly == NULL)
>>> {
>>> mono_image_close(monoEngine->image);
>>> return FALSE;
>>> }
>>>
>>> but it does not seem to work. The code that runs is
>>> always the first loaded one!!
>>>
>>> I also added the following code to my engine:
>>>
>>> mono_trace_set_log_handler(monoLogCallback, NULL);
>>> mono_trace_set_print_handler(monoPrintCallback);
>>> mono_trace_set_printerr_handler(monoPrintCallback);
>>> mono_trace_set_level_string ("debug");
>>>
>>>
>>> but it is reporting debug info only on the first run...
>>> is there a way to having it working on every run?
>>>
>>> Lastly, Is there a way to compile cs source without
>>> launching a
>>>
>>> system("msc.code.cs -target:library");
>>>
>>> thanks in advance
>>>
>>> Pierre
>>>
>>>
>>>
>>> _______________________________________________
>>> Mono-list maillist -Mono-list at lists.dot.net <mailto:Mono-list at lists.dot.net>
>>> http://lists.dot.net/mailman/listinfo/mono-list
>>>
>>> _______________________________________________
>>> Mono-devel-list mailing list
>>> Mono-devel-list at lists.dot.net
>>> <mailto:Mono-devel-list at lists.dot.net>
>>> http://lists.dot.net/mailman/listinfo/mono-devel-list
>>>
>>> --
>>>
>>>
>>>
>>> Ramin Zaghi
>>>
>>> *Mosaic3DX™ | User Interface Technology*
>>> St John's Innovation Centre,
>>> Cowley Road,
>>> Cambridge,
>>> CB4 0WS, UK*
>>> *
>>> *E*:**rzaghi at mosaic3dx.com <mailto:rzaghi at mosaic3dx.com>
>>> *T*: +44 1223 421 311
>>> http://linkedin.com/in/raminzaghi
>>>
>>
>> --
>>
>>
>>
>> Ramin Zaghi
>>
>> *Mosaic3DX™ | User Interface Technology*
>> St John's Innovation Centre,
>> Cowley Road,
>> Cambridge,
>> CB4 0WS, UK*
>> *
>> *E*:**rzaghi at mosaic3dx.com <mailto:rzaghi at mosaic3dx.com>
>> *T*: +44 1223 421 311
>> http://linkedin.com/in/raminzaghi
>>
>> --
>>
>>
>>
>> Ramin Zaghi
>>
>> *Mosaic3DX™ | User Interface Technology*
>> St John's Innovation Centre,
>> Cowley Road,
>> Cambridge,
>> CB4 0WS, UK*
>> *
>> *E*:**rzaghi at mosaic3dx.com <mailto:rzaghi at mosaic3dx.com>
>> *T*: +44 1223 421 311
>> http://linkedin.com/in/raminzaghi
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.dot.net/pipermail/mono-devel-list/attachments/20180221/ec5f217f/attachment-0001.html>
More information about the Mono-devel-list
mailing list