I tried running the sample code which appears on the documentation page for the System.Reflection.Emit.LocalBuilder class but it appears that the calls to LocalBuilder.SetLocalSymInfo(string, int, int) aren't doing anything since the IL Dissasembler shows this as the IL for SampleAssembly.dll:
.method public static string Function1(int32 A_0) cil managed
{
// Code size 10 (0xa)
.maxstack 1
.locals init (string V_0,
int32 V_1)
IL_0000: ldarg.0
IL_0001: stloc.1
IL_0002: ldstr "string value"
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ret
} // end of method Example::Function1
Why aren't the variable names (myString and myInt) listed in the Dissasembler?
Enviroment Info:
Windows 7 64 bit
Visual Studio 2010 Professional SP1
.Net 4.0.30319 SP1
Target Framework: .Net 4 Client Profile
Debug configuration (for the program using System.Reflection.Emit)
Edit: As I noted in a comment, there is a SampleAssembly.pdb file being generated along with the SampleAssembly.dll file.
The debugging support in System.Reflection.Emit is pretty poor and quirky (and to a certain extent this is also true for IKVM.Reflection, because it inherits some of the brokenness from the underlying .pdb writer API that has to be used since the .pdb file format is not documented).
Anyway, the reason the sample doesn't work is that it is missing the following code:
ISymbolDocumentWriter doc = myModule.DefineDocument("sourcefile", Guid.Empty, Guid.Empty, Guid.Empty);
myMethodIL.MarkSequencePoint(doc, 1, 0, 1, 0);
There must be at least a single sequence point in the method, because that is the way the internal data structures are tied together.
Symbol names are stored in the PDB file and not in the assembly.
A tool like Reflector.NET will load the PDB file if present to give your disassembled code better names.
You can also verify this by debugging the code in a debugger with and without the PDB file.
I suspect this is because you are building the module as a release DLL.
Try passing true as the second parameter to AssemblyBuilder.DefineDynamicModule
Related
I have trouble calling Cntk functions from C#. The header file I'm using is CNTKLibraryC.h from a binary CNTK installation, and the DLL that I load is Cntk.Core-2.5.dll from the same installation. My interop signature for CNTK_LoadModel at the moment:
[DllImport(DllName, CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr CNTK_LoadModel(
IntPtr modelFilePath,
IntPtr device,
out IntPtr model);
This "works" if I use the model file name (run through Marshal.StringToHGlobalUni()) for both modelFilePath and device, but I can't call CNTK_ReleaseModel afterwards for then the program crashes. Sometimes I also succeed if I pass a non-existing path to modelFilePath, so it's obvious that the second argument is taken as the model file name, contrary to what the function signature suggests. I suspect there's something I've overlooked here. I am not used to calling native 64 bit DLLs from C#, only 32 bit. What, for instance, is the correct calling convention?
So I'm writing a standalone JScript file to be executed by Windows Script Host (this file is not going to be used as a web application).
My goal is to load a dll file. Just like using LoadLibrary function in a C++ application.
I tried researching the subject but I didn't come up with anything useful. I'm so lost I don't have any piece of code to share. I understand using ActiveXObject may come to my rescue. if so, any idea how to use it?
Update:
If we all agree that loading is impossible, I'll settle for validity check. Meaning, don't try to load but check if it is loaded and functional.
You can export a specific function for this purpose.
Then, from your JScript, execute rundll32.exe and check that the function ran as expected.
You might also give Gilles Laurent's DynaWrap
ocx a chance.
This kind of dll needs to be registered on the target system like regsvr32 /s DynaWrap.dll.
It is restricted to 32-bit DLLs, and this might be inconvenient for you to use, but it works on a 64bit Windows. You can't access function exported by ordinal number and you can't directly handle 64bit or greater values/pointers.
Here's a sample to call MessageBoxA from JScript:
var oDynaWrap = new ActiveXObject( "DynamicWrapper" )
// to call MessageBoxA(), first register the API function
oDynaWrap.Register( "USER32.DLL", "MessageBoxA", "I=HsSu", "f=s", "R=l" )
// now call the function
oDynaWrap.MessageBoxA( null, "MessageBoxA()", "A messagebox from JScript...", 3 )
And here from VBScript:
Option Explicit
Dim oDynaWrap
Set oDynaWrap = CreateObject( "DynamicWrapper" )
' to call MessageBoxA(), first register the API function
UserWrap.Register "USER32.DLL", "MessageBoxA", "I=HsSu", "f=s", "R=l"
' now call the function
UserWrap.MessageBoxA Null, "MessageBoxA()", "A messagebox from VBScript...", 3
To use a function you need to "register" the exported function of your DLL.
To do this you need to call the register method with a first parameter containing a string object to the complete path of the DLL, a second parameter for the exported name of the function to use, and following three paremeters describing the functions declartion in a somehow obscure syntax.
i= describes the number and data type of the functions parameters.
f= describes the type of call: _stdcall or _cdecl. Default to _stdcall.
r= describes the return values data type.
The supported data types are:
Code Variant Description
a VT_DISPATCH IDispatch*
b VT_BOOL BOOL
c VT_I4 unsigned char
d VT_R8 8 byte real
f VT_R4 4 byte real
h VT_I4 HANDLE
k VT_UNKNOWN IUnknown*
l VT_I4 LONG
p VT_PTR pointer
r VT_LPSTR string by reference
s VT_LPSTR string
t VT_I2 SHORT
u VT_UINT UINT
w VT_LPWSTR wide string
Thus the Register method call used in the examples describes MessageBoxA like this:
_stdcall LONG MessageBoxA( HANDLE, LPSTR, LPSTR, UINT );
For a explanation of MessageBoxA look at the docs on MSDN.
Please read the DynaWrap docs for more sophisticated examples... But you might need Google translate, 'cos they are written in french ;-)
To be able to use a dll as ActiveXObject, it needs to be registered as COM object. There are some restrictions on this but if you have a code for this dll, it is certainly doable.
When you register your dll as COM object, it is assigned a name. You use this name to create an object. This example from MSDN uses excel since it is already registered if you installed office.
var ExcelApp = new ActiveXObject("Excel.Application");
var ExcelSheet = new ActiveXObject("Excel.Sheet");
// Make Excel visible through the Application object.
ExcelSheet.Application.Visible = true;
// Place some text in the first cell of the sheet.
ExcelSheet.ActiveSheet.Cells(1,1).Value = "This is column A, row 1";
// Save the sheet.
ExcelSheet.SaveAs("C:\\TEST.XLS");
// Close Excel with the Quit method on the Application object.
ExcelSheet.Application.Quit();
Apart from restriction of registering dll, using dll is no different from using it as c++ or c# dll. Note that, C# (or other .NET dlls) should be ComVisible to be used from javascript this way.
EDIT: The only other way of using C/C++ dll from javascript is swig interfaces. I have not used it, therefore I can only point you in that direction.
SWIG is a software development tool that connects programs written in
C and C++ with a variety of high-level programming languages. SWIG is
used with different types of target languages including common
scripting languages such as Javascript, Perl, PHP, Python, Tcl and
Ruby.
I am working on refactoring a large amount of code from an unmanaged C++ assembly into a C# assembly. There is currently a mixed-mode assembly going between the two with, of course, a mix of managed and unmanaged code. There is a function I am trying to call in the unmanaged C++ which relies on FILE*s (as defined in stdio.h). This function ties into a much larger process which cannot be refactored into the C# code yet, but which now needs to be called from the managed code.
I have searched but cannot find a definitive answer to what kind of underlying system pointer the System::IO::FileStream class uses. Is this just applied on top of a FILE*? Or is there some other way to convert a FileStream^ to a FILE*? I found FileStream::SafeFileHandle, on which I can call DangerousGetHandle().ToPointer() to get a native void*, but I'm just trying to be certain that if I cast this to FILE* that I'm doing the right thing...?
void Write(FILE *out)
{
Data->Write(out); // huge bulk of code, writing the data
}
virtual void __clrcall Write(System::IO::FileStream ^out)
{
// is this right??
FILE *pout = (FILE*)out->SafeFileHandle->DangerousGetHandle().ToPointer();
Write(pout);
}
You'll need _open_osfhandle followed by _fdopen.
Casting is not magic. Just because the input and types output are right for your situation doesn't mean the values are.
I have a project where I have a directory called plugins/ which will contain multiple DLLs.
As an example, I will have two (2) DLLs in my plugins/ directory: Visual.dll and Momen.dll
Each of those will be a Class, Visual.dll will have the Class name Visual and Momen.dll will have the Class name Momen.
I need to make a loop that will loop through all DLL files in my plugins/ directory; once in that loop, it will obviously know the file is Visual.dll or Momen.dll. First, it will need to include the DLLs (just as if I added them as References to my Project) so that I can use them. If the loop is at Visual.dll, I will then need it to create an instance of the Visual Class, and then execute a method called Run()
I'm a PHP developer, and relatively new to VB.NET, in PHP I'd be able to do something like, which would create a new instance of my Visual Class (while passing a few arguments), then execute the Run() method:
$className = "Visual";
$instance = new $className("arg1", "arg2");
$instance->Run();
I appreciate any help.
Thank you
If the DLLs are .NET assemblies, then you can load them with Assembly.LoadFile. That will give you a reference to an Assembly object.
You can use the assembly's GetExportedTypes method to view public types in the assembly, or the GetType overload that takes a string parameter to get a type from the assembly based on its name.
From there, you should be able to use an appropriate overload of Activator.CreateInstance to create an instance of the class. From there, you should also be able to find and run its Run method through reflection.
Edit This is untested, but something like this might work (or be close to working):
Dim plugin As Assembly = Assembly.LoadFile("test.dll")
Dim pluginType As Type = plugin.GetType("Test")
Dim instance As Object = Activator.CreateInstance(pluginType)
Dim runMethod As MethodInfo = pluginType.GetMethod("Run")
Dim param1 As String = "Hello"
Dim param2 As String = "World"
runMethod.Invoke(instance, New Object() {param1, param2})
If you're going to do much with plugins other than just load and run a method, then it might be worthwhile to look for a plugin framework to use.
I have some .net code that generates an assembly then runs it. It has worked reliably under .net for some time. Under Mono the code works on some non-trivial instances but on others it dies with an illegal IL exception.
When attempting to isolate the problem I cut it down to the point where it just returns a native int. The example works fine under .net and dies under Mono. Reflector says the code is as follows, and this is as expected:
.method public hidebysig static native int Main() cil managed
{
.maxstack 8
L_0000: ldc.i8 4
L_0009: ret
}
The exception I get is: System.InvalidProgramException: Invalid IL code in HelloWorldType:Main (): IL_0009: ret
What am I doing wrong, please?
I would guess: An i8 is not considered the same type as a native int. If you want to return a native int, you'd need a conv.i in the middle. A native int is 8 bytes on a 64-bit platform but only 4 bytes on a 32-bit platform.