public unsafe Future <byte[]> Send(RPCMessage message, bool wantResponse)
{
if (_Process == null)
{
throw new Exception("No remote process");
}
if (RemoteThreadId == 0)
{
throw new Exception("No remote thread");
}
UInt32 messageSize = (UInt32)Marshal.SizeOf(typeof(TransportRPCMessage));
UInt32 moduleNameSize = TransportStringSize(message.ModuleName);
UInt32 functionNameSize = TransportStringSize(message.FunctionName);
UInt32 textSize = TransportStringSize(message.Text);
Future <byte[]> result = null;
UInt32 messageID = 0;
if (wantResponse)
{
messageID = GetMessageID();
result = new Future <byte[]>();
_AwaitingResponses[messageID] = result;
}
using (var handle = Win32.OpenProcessHandle(ProcessAccessFlags.VMWrite | ProcessAccessFlags.VMOperation, false, _Process.Id)) {
RemoteMemoryRegion region;
var regionSize = messageSize + moduleNameSize + textSize + functionNameSize;
var buffer = new byte[regionSize];
// leaked on purpose
region = RemoteMemoryRegion.Allocate(
_Process, handle, regionSize
);
object transportMessage = new TransportRPCMessage {
Type = message.Type,
MessageId = messageID,
Text = WriteTransportString(message.Text, buffer, messageSize, region.Address),
FunctionName = WriteTransportString(message.FunctionName, buffer, messageSize + textSize, region.Address),
ModuleName = WriteTransportString(message.ModuleName, buffer, messageSize + textSize + functionNameSize, region.Address)
};
fixed(byte *pBuffer = buffer)
{
Marshal.StructureToPtr(transportMessage, new IntPtr(pBuffer), false);
try {
region.Write(handle, 0, regionSize, pBuffer);
} catch {
try {
region.Dispose();
} catch {
}
throw;
}
}
if (!Win32.PostThreadMessage(RemoteThreadId, WM_RPC_MESSAGE, region.Address, region.Size))
{
var error = Win32.GetLastError();
region.Dispose();
throw new Exception(String.Format("Error posting thread message: {0:x8}", error));
}
}
return(result);
}