After hours of experimenting (why!?!?!?), I think the problem is
somewhere in the IDispatch implementation. The Interop assembly
generated by VS2008 appears to use te IDispatch interface to call
VirtualBox functions. I think the Interop assembly expects an array of
unsigned bytes on the .Net side, while VirtualBox uses signed bytes...
So, after some crashes of both my own code and the VirtualBox VM, I came
up with the attached C# code:
- Standard output works, although it is ugly and unreliable with the
timed wait
- Standard input hangs the VM process. Be careful with this, you may
have to kill the running VM! If VBox hangs here, you may still shut down
the guest OS via remote desktop, and VBox will get stuck in the Stopping
state. Bug report?
Ivo
Op 31-5-2013 13:05, Magnus Madsen schreef:
LeeEll <info@...> writes:
I have change the code so i execute ipconfig directly (not via cmd.exe)
but i can't get the output from it.
I don't understand why this happens. The output type for Read method is
System.Array.
I really need help with this!!!!!!!!
Hi LeeEll,
Are you still having issues with this problem?
I've been working on utilizing the VirtualBox interface through .NET,
and was not able to find much information on it.
Please let me know if I should elaborate, but I can let you know that it
is,
to my knowledge, simply not possible to directly access those functions in
the
VirtualBox API that return binary data as an array from .NET.
I am not entirely sure why, but the SafeArray type returned cannot be
marshalled correctly.
What I ended up doing was writing a simple wrapper in unmanaged C++ to
create
a new "normal" SafeArray of bytes and returning that to my .NET application.
Using the wrapper I was able to successfully return output data from a
process
I've created from the host. I haven't tried sending input to a process, but
looking at IProcess::write it requires the same kind of parameter:
IProcess::write(
[in] unsigned long handle,
[in] unsigned long flags,
[in] octet data[],
[in] unsigned long timeoutMS)
Therefore it is probably also not possible to send data to a process
without
using a wrapper.
Let me know if you want the source for the wrapper; it's quite simple.
Kind regards,
Magnus
_______________________________________________
vbox-dev mailing list
[email protected]
https://www.virtualbox.org/mailman/listinfo/vbox-dev
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using VirtualBox;
namespace ConsoleApplication1 {
[Guid("DFA39A36-5D43-4840-A025-67EA956B3111")]
[TypeLibType(4160)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
interface IProcessA {
Array Arguments { get; }
Array Environment { get; }
string ExecutablePath { get; }
int ExitCode { get; }
string Name { get; }
uint PID { get; }
ProcessStatus Status { get; }
ProcessWaitResult WaitFor(uint aWaitFor, uint aTimeoutMS);
ProcessWaitResult WaitForArray(Array aWaitFor, uint aTimeoutMS);
[return: MarshalAs(UnmanagedType.SafeArray,
SafeArraySubType=VarEnum.VT_I1)]
Array Read(uint aHandle, uint aToRead, uint aTimeoutMS);
uint Write(uint aHandle, uint aFlags,
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_I1)] Array
aData, uint aTimeoutMS);
uint WriteArray(uint aHandle, Array aFlags, Array aData, uint
aTimeoutMS);
void Terminate();
}
class Program {
private static SByte ByteToSByteConverter(Byte b) { return
(SByte)b; }
unsafe static void Main(string[] args) {
VirtualBoxClient vboxclient = new VirtualBoxClient();
IMachine machine =
vboxclient.VirtualBox.FindMachine("x");
Session session = vboxclient.Session;
try {
machine.LockMachine(session,
LockType.LockType_Shared);
IGuestSession guestsession =
session.Console.Guest.CreateSession("x", "x", "", "DotNet Test");
try {
//Call "cmd.exe /c echo hi" which will
print "hi" to stdout
IGuestProcess process =
guestsession.ProcessCreate("cmd.exe", new String[] { "/c", "echo", "hi" }, new
String[0], new ProcessCreateFlag[] {
ProcessCreateFlag.ProcessCreateFlag_WaitForStdOut }, 0);
//Call "cmd.exe", which should accept
commands via stdin...
//IGuestProcess process =
guestsession.ProcessCreate("cmd.exe", new String[] { }, new String[0], new
ProcessCreateFlag[] { ProcessCreateFlag.ProcessCreateFlag_WaitForStdOut }, 0);
//Cast process handle to correct
interface
IProcessA processa = (IProcessA)process;
//Wait for process to start
process.WaitForArray(new
ProcessWaitForFlag[] { ProcessWaitForFlag.ProcessWaitForFlag_Start }, 0);
//Provide input via stdin
//Warning! Using this may hang your VM
process!!!
//Byte[] bytesin =
Encoding.UTF8.GetBytes("echo hi\r\nexit\r\n");
//processa.Write(0,
(uint)ProcessInputFlag.ProcessInputFlag_EndOfFile, Array.ConvertAll<Byte,
SByte>(bytesin, ByteToSByteConverter), 0);
//Wait for process to end
process.WaitForArray(new
ProcessWaitForFlag[] { ProcessWaitForFlag.ProcessWaitForFlag_Terminate }, 500);
//Read output from stdout
Array bytes = processa.Read(1, 64 *
1024, 0);
Console.WriteLine(bytes.Length);
Console.WriteLine(Encoding.UTF8.GetString((Byte[])bytes));
} finally {
guestsession.Close();
}
} finally {
if (session.State ==
SessionState.SessionState_Locked) session.UnlockMachine();
}
Console.ReadLine();
}
}
}
_______________________________________________
vbox-dev mailing list
[email protected]
https://www.virtualbox.org/mailman/listinfo/vbox-dev