I am trying to invoke a mono function natively through mono-2.0-bdwgc exports.
auto image = mono::image_loaded( "mscorlib" );
if ( !image )
return;
auto domain = mono::get_root_domain( );
if( !domain )
return;
mono::thread_attach( domain );
auto klass = mono::class_from_name( image, "System.Collections.Generic", "Dictionary`2" );
auto method = mono::class_get_method_from_name( klass, "TryInsert", 3 );
auto compiled_ptr = mono::compile_method( method );
"compiled_ptr" returns 0. It appears these functions do not contain any data? I am unsure if it can be accessed through an ICALL.
Related
I having trouble to send FNC1 symbol from my C# software to the printer through network communication.
The printer is Hitachi IJP 2D barcode printer, I had try to use the example from the SDK but there is only able to pass the string/character to the printer.
There sample code is as below :
if ( null == this.ijp )
{
throw new InvalidOperationException ( "Do connect the ink jet printer." );
}
// Get the current message.
IJPMessage message = ( IJPMessage ) this.ijp.GetMessage ();
if ( 2 > message.Items.Count )
{
message.AddColumn ();
}
// Change a text.
message.Items[ 1 ].Text = newText;
// Set the message.
this.ijp.SetMessage ( message );
Does anyone know how to list NTFS permissions on all shares in a NETAPP vfiler using C#?
I tried to use NETAPP API but only get the share permissions, can't find a way to get the NTFS ones.
EDIT
Thanks Sobrique, here's the C# syntax:
var api = new NaElement("system-cli");
var args = new NaElement("args");
args.AddNewChild("arg", "fsecurity");
args.AddNewChild("arg", "show");
args.AddNewChild("arg", path);
api.AddChildElement(args);
s.InvokeElem(api)
For doing this though, I tend to use:
vfiler run vfilername fsecurity show /path/to/file/here
This will print the various ACL attributes (NTFS and Unix) for the file in question. You'll need to first enumerate your share paths to do this. (cifs shares is a start point).
There is a way to do it via the API - you need to use the undocumented 'system-cli' function that lets you remote execute commands and capture output.
Unfortunately doing this the output is ... about on a par with just running an ssh command.
However - craft your XML:
<!DOCTYPE netapp SYSTEM "/na_admin/netapp_filer.dtd">
<netapp version="1.7" xmlns="http://www.netapp.com/filer/admin">
<system-cli>
<args>
<arg>fsecurity</arg>
<arg>show</arg>
<arg>/vol/volname/qtreename/sharename/filename</arg>
</args>
</system-cli>
</netapp>
This will do the trick, although it will return you plain text cli-output element.
use strict;
use warnings;
use XML::Twig;
use LWP;
my $twig = XML::Twig->new( 'pretty_print' => 'indented' );
$twig->set_root(
XML::Twig::Elt->new(
'netapp',
{ version => 1.7,
vfiler => "somevfiler",
xmlns => "http://www.netapp.com/filer/admin",
},
)
);
my $api_req = $twig->root->insert_new_elt('system-cli');
my $args = $api_req->insert_new_elt('args');
$args->insert_new_elt( 'last_child', 'arg', 'fsecurity' );
$args->insert_new_elt( 'last_child', 'arg', 'show' );
$args->insert_new_elt( 'last_child', 'arg', '/vol/volname/qtree/filename' );
$twig->set_doctype('netapp SYSTEM "file:/etc/netapp_filer.dtd"');
$twig->set_xml_version("1.0");
$twig->set_encoding('utf-8');
$twig->print;
exit;
my $user_agent = LWP::UserAgent->new(
'ssl_opts' => {
'verify_hostname' => 0,
'SSL_version' => 'SSLv3',
}
);
my $request =
HTTP::Request->new( 'POST' =>
'https://myfilername/servlets/netapp.servlets.admin.XMLrequest_filer'
);
$request->authorization_basic( 'username_here', 'password_here' );
$request->content( $twig->sprint );
my $results = $user_agent->request($request);
if ( not $results->is_success ) {
print "Error: ", $results->status_line;
exit;
}
my $results_xml = XML::Twig->new( 'pretty_print' => 'indented_a' );
$results_xml->parse( $results->content );
$results_xml->print;
I have an MSI file built from my C# Visual Studio 2010. The version is set through the Version property. I wanted to know if there is a way to determine the version without having to install the file. Currently when right click and view the properties it isn't displayed.
The following code may be helpful. But remember that you should first add a COM reference to the Microsoft Windows Installer Object Library and add the WindowsInstaller namespace to your code. The following function may be what you need.
public static string GetMsiInfo( string msiPath, string Info)
{
string retVal = string.Empty;
Type classType = Type.GetTypeFromProgID( “WindowsInstaller.Installer” );
Object installerObj = Activator.CreateInstance( classType );
Installer installer = installerObj as Installer;
// Open msi file
Database db = installer.OpenDatabase( msiPath, 0 );
// Fetch the property
string sql = String.Format(“SELECT Value FROM Property WHERE Property=’{0}’”, Info);
View view = db.OpenView( sql );
view.Execute( null );
// Read in the record
Record rec = view.Fetch();
if ( rec != null )
retVal = rec.get_StringData( 1 );
return retVal;
}
If you need the version, pass in the name of the MSI file you want, e.g.
string version = GetMsiInfo( "d:\product.msi", “ProductVersion” );
Yes - I think you need to inspect the MSI database however, which requires either some API calls or a wrapper utility.
Microsofts ORCA application should let you do this (although I've never tried it myself).
Instead of using the COM library, you can use the Microsoft.Deployment.WindowsInstaller library from the wixtoolset SDK. Once referenced, you can very similarly get the version info.
private string GetMsiInfo(string msiPath)
{
using (var database = new Microsoft.Deployment.WindowsInstaller.Database(msiPath))
{
var sql = "SELECT Value FROM Property WHERE Property ='ProductVersion'";
using (var view = database.OpenView(sql))
{
view.Execute();
using (var record = view.Fetch())
{
var version = record?.GetString(1);
return version;
}
}
}
}
I haven't found a way to get the correct assembly via nuget installer. However, after I installed the wixtoolset https://wixtoolset.org/releases/, I was able to add a reference in my project directly under assemblies -> extensions -> Microsoft.Deployment.WindowsInstaller.
Based on Gupta's answer, I added COM release calls. If you want to recreate or replace the file you accessed in your further workflow, it might be still in use and you will get an exception if the GC did not yet release the objects, so let's do this manually.
public static string GetMsiInfo(string msiPath, string info)
{
string retVal = string.Empty;
Type classType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
dynamic installer = Activator.CreateInstance(classType);
try
{
// Open msi file
var db = installer.OpenDatabase(msiPath, 0);
try
{
// Fetch the property
string sql = $"SELECT Value FROM Property WHERE Property ='{info}'";
var view = db.OpenView(sql);
try
{
view.Execute(null);
// Read in the record
var rec = view.Fetch();
if (rec != null)
retVal = rec.StringData(1);
return retVal;
}
finally
{
view.Close();
Marshal.ReleaseComObject(view);
}
}
finally
{
//db.Commit();
Marshal.ReleaseComObject(db);
}
}
finally
{
Marshal.ReleaseComObject(installer);
}
}
I think using this code, there is no need to add a COM reference or an extra namespace as mentioned by Gupta, because we use late binding here (see the dynamic).
I am going to ask a question that might sound weird.
Is there a way to build a new class during Runtime? Or at least, add a new property to an existing class.
I mean creating a class that doesn't exist and not an instance of an existing class. I could later on use reflections to load and use this class.
Adding a property to an existing type is not possible, but you can create a new type at runtime using Reflection.Emit. It's pretty complicated stuff, and it goes something like this:
AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(
assemblyName , AssemblyBuilderAccess.Run, assemblyAttributes);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("ModuleName");
TypeBuilder typeBuilder = moduleBuilder.DefineType(
"MyNamespace.TypeName" , TypeAttributes.Public);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
// Add a method
newMethod = typeBuilder.DefineMethod("MethodName" , MethodAttributes.Public);
ILGenerator ilGen = newMethod.GetILGenerator();
// Create IL code for the method
ilGen.Emit(...);
// ...
// Create the type itself
Type newType = typeBuilder.CreateType();
This code is just a sample. It could contain errors.
You can also generate classes by compiling C# source code at runtime using System.CodeDom, but I don't know a lot about that.
Take a look at the System.Reflection.Emit namespace. I've never used it myself but the classes in this namespace can be used to generate IL (intermediate language).
This is not a weird question - in some cases it might be very useful. For instance I use this technique for performance tests sometimes:
public static Type[] DynamicTypes;
public void CreateObjects()
{
var codeNamespace = new CodeNamespace( "DynamicClasses" );
codeNamespace.Imports.Add( new CodeNamespaceImport( "System" ) );
codeNamespace.Imports.Add( new CodeNamespaceImport( "System.ComponentModel" ) );
for( var i = 0; i < 2000; i++ )
{
var classToCreate = new CodeTypeDeclaration( "DynamicClass_" + i )
{
TypeAttributes = TypeAttributes.Public
};
var codeConstructor1 = new CodeConstructor
{
Attributes = MemberAttributes.Public
};
classToCreate.Members.Add( codeConstructor1 );
codeNamespace.Types.Add( classToCreate );
}
var codeCompileUnit = new CodeCompileUnit();
codeCompileUnit.Namespaces.Add( codeNamespace );
var compilerParameters = new CompilerParameters
{
GenerateInMemory = true,
IncludeDebugInformation = true,
TreatWarningsAsErrors = true,
WarningLevel = 4
};
compilerParameters.ReferencedAssemblies.Add( "System.dll" );
var compilerResults = new CSharpCodeProvider().CompileAssemblyFromDom( compilerParameters, codeCompileUnit );
if( compilerResults == null )
{
throw new InvalidOperationException( "ClassCompiler did not return results." );
}
if( compilerResults.Errors.HasErrors )
{
var errors = string.Empty;
foreach( CompilerError compilerError in compilerResults.Errors )
{
errors += compilerError.ErrorText + "\n";
}
Debug.Fail( errors );
throw new InvalidOperationException( "Errors while compiling the dynamic classes:\n" + errors );
}
var dynamicAssembly = compilerResults.CompiledAssembly;
DynamicTypes = dynamicAssembly.GetExportedTypes();
}
You might take a look at the System.CodeDom namespace. According to one of the pages linked from there:
The .NET Framework includes a mechanism called the Code Document Object Model (CodeDOM) that enables developers of programs that emit source code to generate source code in multiple programming languages at run time, based on a single model that represents the code to render.
I'm not at all an expert in this, I just remembered seeing it on my .NET Framework poster on my wall. :)
Edit: Since writing this answer, I have played with System.CodeDom a bit. I've written a blog post that uses some basic CodeDom that may help those wanting to get started with it.
I am compiling a dynamic assembly at runtime. It needs to reference another dll. Everything works alright, as long as I set an OutputAssembly in my CompilerParameters. But as soon as I set GenerateInMemory = true; it fails:
var compilerParameters = new CompilerParameters();
if( compileInMemory )
compilerParameters.GenerateInMemory = true;
else
compilerParameters.OutputAssembly = "<my_dynamic_dll_path>";
compilerParameters.ReferencedAssemblies.Add( "<other_dll_path>" );
var compilerResults = new CSharpCodeProvider().CompileAssemblyFromDom( compilerParameters, codeCompileUnit );
// Here: compilerResults.Errors.HasErrors == false
foreach( var type in compilerResults.CompiledAssembly.GetTypes() )
{
// Exception:
// Unable to load one or more of the requested types.
// Retrieve the LoaderExceptions property for more information.
}
The LoaderExceptions are telling me that "other_dll" could not be found. Why is it working as long as I do not compile in-memory and what do I have to do to make it working in-memory?
There is no loading context when you use GenerateInMemory, the assembly gets loaded by the Assembly.Load(Byte[]) overload. One workaround is to temporarily hook the AppDomain.AssemblyResolve event so you can load "other_dll" yourself.