> From the MSDN topic on DynamicMethod I've been able to create a very simple
> dynamic method. Following the sample code for DynamicMethod, my method uses
[quoted text clipped - 9 lines]
> There's some other code, but this is unchanged from the earlier version that
> used GetILGenerator and Emit calls.
Here's sample code along those lines:
---8<---
using System;
using System.Reflection.Emit;
using System.Reflection;
using System.IO;
class Program
{
delegate void Method();
static void Main()
{
DynamicMethod dynMeth = new DynamicMethod("foo",
typeof(void), new Type[0], typeof(Program));
// the "easy" way
//WriteHello(dynMeth.GetILGenerator());
// the "hard" way
WriteHelloViaBytes(dynMeth.GetDynamicILInfo());
Method meth = (Method) dynMeth.CreateDelegate(typeof(Method));
meth();
}
static void WriteHelloViaBytes(DynamicILInfo info)
{
MethodInfo writeLineMethod =
typeof(System.Console).GetMethod("WriteLine",
new Type[] { typeof(string) });
int writeLineToken = info.GetTokenFor(
writeLineMethod.MethodHandle);
int helloWorldToken = info.GetTokenFor("Hello World!");
MemoryStream codeStream = new MemoryStream();
BinaryWriter codeWriter = new BinaryWriter(codeStream);
codeWriter.Write((byte) OpCodes.Ldstr.Value);
codeWriter.Write(helloWorldToken);
codeWriter.Write((byte) OpCodes.Call.Value);
codeWriter.Write(writeLineToken);
codeWriter.Write((byte) OpCodes.Ret.Value);
codeWriter.Flush();
info.SetCode(codeStream.ToArray(), 1);
MemoryStream sigStream = new MemoryStream();
BinaryWriter sigWriter = new BinaryWriter(sigStream);
// Signature format is tricky, described in 23.3 of
// ECMA 335; see also CorHdr.h of .NET SDK.
// Takes some time to work out; it's not well
// described, IMHO.
// IMAGE_CEE_CS_CALLCONV_LOCAL_SIG from CorHdr.h
sigWriter.Write((byte) 0x7);
// no of parameters (signatures follow return type, recursively)
sigWriter.Write((byte) 0);
// return type; here I use ELEMENT_TYPE_VOID as in CorHdr.h
sigWriter.Write((byte) 1);
sigWriter.Flush();
info.SetLocalSignature(sigStream.ToArray());
}
static void WriteHello(ILGenerator cg)
{
cg.Emit(OpCodes.Ldstr, "Hello World!");
cg.Emit(OpCodes.Call,
typeof(System.Console).GetMethod("WriteLine",
new Type[] { typeof(string) }));
cg.Emit(OpCodes.Ret);
}
}
--->8---
Be aware that you need to create tokens for all things imported into the
dynamic method; this is a PIA, as is generating the signature. I don't
think you gain a lot by avoiding ILGenerator, unless you've got an
existing .NET compiler and you want to leverage it for DynamicMethod.
> The new version throws BadImageFormatException when I call the delegate
> that's tied to the dynamic method. One of the trouble-shooting tips advises
> me to make sure that the file image is a valid managed assembly.
The "file image" is certainly true for an assembly loaded by bytes, but
the data provided to DynamicMethod is not an entire assembly. It's 4
things:
1) Tokens created for imports, used in code bytes etc.; not just any
bytes will do, they need to be patched up for imports
2) Signature bytes of the method
3) Code bytes
4) Exception bytes
... and they need to be all poked in individually via DynamicILInfo,
like above.
-- Barry

Signature
http://barrkel.blogspot.com/
Barry Kelly - 07 Apr 2007 14:22 GMT
> // Signature format is tricky, described in 23.3 of
> // ECMA 335; see also CorHdr.h of .NET SDK.
[quoted text clipped - 7 lines]
> // return type; here I use ELEMENT_TYPE_VOID as in CorHdr.h
> sigWriter.Write((byte) 1);
And it's a demonstration proof of its trickiness: the above is the
format for a method signature, not local variables signature. Doh!
This is described in section 23.2.6, part II, ECMA 335.
IMAGE_CEE_CS_CALLCONV_LOCAL_SIG is 0x7, and is the first part of the
locals signature. Second byte is count (number of locals); and that's
it, the signatures for the locals follow. The code quoted above should
read thusly:
---8<---
// Signature format is tricky, described in 23.3 of
// ECMA 335; see also CorHdr.h of .NET SDK.
// Takes some time to work out; it's not well
// described, IMHO.
// IMAGE_CEE_CS_CALLCONV_LOCAL_SIG from CorHdr.h
sigWriter.Write((byte) 0x7);
// no of locals (signatures follow, recursively)
sigWriter.Write((byte) 0);
--->8---
It doesn't make practical runtime difference, however; the extra '0'
byte in the parent post is ignored.
-- Barry

Signature
http://barrkel.blogspot.com/
Mark_Parker - 09 Apr 2007 19:44 GMT
Thanks, Barry. It was indeed the signature that I was missing. Your example
got me started and section 23 of ECMA 335 gave me the information I needed to
insert the right bytes into the signature.
So in a nutshell, what I have is one stream of IL code bytes for the method,
and another stream of attribute bytes representing, respectively, the
calling convention (IMAGE_CEE_CS_CALL_CONV_LOCAL_SIG), the number of
parameters (2 in the case of my method), the return type (long), and a byte
each for the types of the parameters (int for both).
Mark
> > // Signature format is tricky, described in 23.3 of
> > // ECMA 335; see also CorHdr.h of .NET SDK.
[quoted text clipped - 34 lines]
>
> -- Barry
I think that the RAIL(Runtime Assembly Instrumentation Library) may help
http://csharp-source.net/open-source/aspect-oriented-frameworks/runtime-assembly
-instrumentation-library
My be a litter later :-)
> From the MSDN topic on DynamicMethod I've been able to create a very
> simple
[quoted text clipped - 21 lines]
>
> Is there a way to do what I want to do?