|
Shame on me I didn't notice your reply. First of all, thanks for your valuable help!
I stand corrected about the Ldnull, as I've been doing a test very similar to yours and it gave me the same result. I was linking "void" to a null push to the stack before the ret statement. Funny, but not working.
I have reproduced the AccessViolationException by adding many "ld_arg0" instructions.
<code>
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, methodInfo);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, methodInfo);
</code>
I was trying to call the same method twice in your example. I've already found two bugs in my IL generation methods thanks to you.
Here's the problem showing the key to my initial idea:
<code>
public class Program
{
delegate void MyDelegate();
public void TestMethod() { Console.WriteLine("Hello"); }
public void TestMethod2() { Console.WriteLine("hey"); }
public static void Main()
{
Program p = new Program();
MethodInfo methodInfo = p.GetType().GetMethod("TestMethod");
MethodInfo methodInfo2 = p.GetType().GetMethod("TestMethod2");
DynamicMethod dynMethod = new DynamicMethod("DynTestMethod",
null, null, typeof(Program));
ILGenerator gen = dynMethod.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, methodInfo);
gen.Emit(OpCodes.Call, methodInfo2);
gen.Emit(OpCodes.Ret);
MyDelegate d = (MyDelegate)dynMethod.CreateDelegate(typeof(MyDelegate));
d.Invoke();
Console.ReadLine();
}
}
</code>
The program gives an "InvalidProgramException" as expected. I wonder if there's a way to make that second Call instruction work. And others, if need be.
Many thanks again for your help and sorry for the delay of this reply.
Roberto
Edit: here's another pseudo-msil dump of what I'm trying to get to run:
<code>
.method void ManagedProcessInput
{
ldarg_0
call void UserInterface.ProcessInput()
call void UserInterfaceEditor.ProcessInput()
ret
}
</code>
Note: the methods stored in the MethodInfos are not static. Moreover, they are implementations of an interface.
<code>
interface IMyInterface
{
void Run();
}
class MyObject : IMyInterface
{
[ctor / dtor]
public void Run()
{
[impl. here]
}
}
</code>
-- modified at 20:04 Saturday 13th January, 2007
|
|
|
|
|
I can't believe I missed it earlier, but the source of your problem is that the dynamically generated method is added as a static method. Being a static method, it does not have a this parameter, so a valid object reference needs to be passed. In my sample code, that would mean that MyDelegate would be modified like this
delegate void MyDelegate(Program p); . The dynamic method's constructor would look like this
DynamicMethod dynMethod = new DynamicMethod("DynTestMethod", null, new Type[] { typeof(Program) }, typeof(Program));
and the dynamic method invocation would look like this
d.Invoke(p);
At the C# level, the generated method would look like this
class Program
{
...
static void DynMethod(Program p)
{
p.TestMethod();
p.TestMethod2();
}
}
As you can see, earlier, there was no parameter being passed to the static method at all, which resulted in the weird exception you got.
In your case, the simplest way would be to make m_MSILMethod accept parameters for all types on which methods would be invoked in its body.
1. In the constructor of the dynamic methods, you would need to provide all the types whose methods would be invoked (all elements in the m_TypeExecutionOrder array?)
2. The m_ILGenerator.Emit(OpCodes.LdArg_0) would obviously need to be modified to point to the correct parameter type.
Something like this should work fine
DynamicMethod m_MSILMethod;
ILGenerator m_ILGenerator;
foreach (string m_InterfaceMethod in m_InterfaceMethods)
{
[...].
m_MSILMethod = new DynamicMethod(String.Format("Managed{0}", m_InterfaceMethod), null, m_TypeExecutionOrder.ToArray(), typeof(MyManager));
m_ILGenerator = m_MSILMethod.GetILGenerator();
int index = 0;
foreach (Type m_Type in m_TypeExecutionOrder)
{
foreach (MethodInfo m_Method in m_Methods[m_Type])
{
if (m_Method.Name == m_InterfaceMethod)
{
m_ILGenerator.Emit(OpCodes.Ldarg, index);
m_ILGenerator.Emit(OpCodes.Call, m_Method);
}
}
index++
}
m_ILGenerator.Emit(OpCodes.Ret);
m_MSILMethods.Add(m_InterfaceMethod, (SpecificDelegate)m_MSILMethod.CreateDelegate(typeof(SpecificDelegate)));
SpecificDelegate 's signature would need to be modified to something like
delegate void SpecificDelegate(MyObject obj1, YourObject obj2, othertypes...);
And of course, when calling the method, you would need to provide instances of all those types specified in the parameter list. Something like
MyObject obj1 = new MyObject();
YourObject obj2 = new YourObject();
m_InterfaceMethod.Invoke(obj1, obj2);
If this looks too ugly, you could have a single object exposing properties for getting the required object references and pass that single object to the dynamically generated method. The IL, of course, would change and would be more complex (you would need to generate code for getting object references from properties).
Hope this helps.
|
|
|
|
|
I am going to implement this and post my results in a post edit.
I am really grateful for the help you've given so far.
Best regards,
Roberto
-- modified at 20:01 Monday 15th January, 2007
|
|
|
|
|
Here's what I've done after your post. Sadly, there's still a bothering issue.
<code> delegate void PlugInMethodDelegate(object[] Instances);
m_MSILMethod =
new DynamicMethod(String.Format("Managed{0}", m_InterfaceMethod),
null, m_Params.ToArray(), typeof(PlugInManager));
PlugInMethodDelegate m_Delegate = (PlugInMethodDelegate)m_MSILMethod.CreateDelegate
(typeof(PlugInMethodDelegate));
</code>
I cannot understand why the CreateDelegate method gives back an error - since the argument is just an object array, after all. Or there's something am I missing again?
PlugInManager: [ERROR] CreateMSILMethods(): Error binding to target method.
at System.Delegate.CreateDelegate(Type type, Object target, RuntimeMethodHandle method)
at System.Reflection.Emit.DynamicMethod.CreateDelegate(Type delegateType)
at Dreams.PlugInManager.CreateMSILMethodsLookup() in C:\xxxx.cs:line 1280
<code> List< Type > m_Params;
</code>
Here's the pseudo-msil dump:
<code>.method void ManagedPreRender(UserInterface, UserInterfaceEditor)
{
ldarg 0
call void UserInterface::PreRender()
ldarg 1
call void UserInterfaceEditor::PreRender()
ret
}
</code>
Better than before, I hope.
Many thanks again.
|
|
|
|
|
I think I might be able to figure out this on my own.
Thanks for the help so far!
r.
|
|
|
|
|
I don't think object[] will do. Having an object array as parameter is different from having a list of parameters. You should either modify the delegate to take the list of objects as a parameter, or modify the dynamically generated method to take an object array as a parameter and then read objects off the array, cast them (but you wouldn't know the type, so this will require additional parameters to the method) and call methods on the objects. I think the first approach i.e modifying the delegate signature would be the easiest to implement.
|
|
|
|
|
I managed to make it work with a object[] argument.
Thanks for your support so far, it's been very precious.
Regards,
Roberto
|
|
|
|
|
I have a sorted DataGridView and I need to make a change to the DataSet that is bound to the DataGridView. Here's the code I'm using:
void DataGrid_CellValueChanged(object sender, DataGridViewCellEventArgs e)<br />
{<br />
BindingManagerBase bindingManager = null;<br />
bindingManager = DataGrid.BindingContext[DataGrid.DataSource, DataGrid.DataMember];<br />
DataRow findRow = ((DataRowView)bindingManager.Current).Row;<br />
int datasetIndex = DataSet.Tables["table1"].Rows.IndexOf(findRow);<br />
}
From what I understand, the IndexOf() method should take the row and find the index of it in the dataset. My problem is it's always coming back as 0. Can anyone see a problem with my code. Thanks!
KubeLife.com
|
|
|
|
|
The indeces do not change after sorting. They correspond to what you had when you initially populated the grid.
SkyWalker
|
|
|
|
|
Hmm, them I must still be doing something wrong. The sender variable shows the RowIndex to be 0 when I know it should be 3 in the DataGridView. I also checked the sender.CurrentRow variable and it also says the index is 0. Any ideas on why this is happening? Thanks SkyWalker!
|
|
|
|
|
Use instead the e.ColumnIndex and e.RowIndex where e is the
DataGridViewCellEventArgs parameter passed to the event handler.
SkyWalker
|
|
|
|
|
My bad, in my previous post I meant to say I used the e.RowIndex variable and it was still 0 when it should have been 3. Here's my sorting code, could there be a problem there?
DataGrid.DataSource = DataSet.Tables["Table1"].DefaultView;<br />
ListSortDirection sortDirection = new ListSortDirection();<br />
sortDirection.Equals("Ascending");<br />
DataGrid.Sort(Column1, sortDirection);
|
|
|
|
|
Try set the DataSource property after sorting (eventually perform a Refresh()
SkyWalker
|
|
|
|
|
Setting the DataSource after the sort didn't do anything. I trying doing a refresh, but it didn't help either. I'm stumped!
|
|
|
|
|
I have to leave the forum now.
If you want, you can send the application zipped to my e-mail, and I'll have a look at it on Monday. Is that ok for you?
SkyWalker
|
|
|
|
|
I'd like to, but I don't think the bosses would like me sending it out =). Thanks for your help though!
|
|
|
|
|
Try looking at binding teh DataGridView to a BindingSource instead of a datatable. You can actually apply sorts/filtering/etc to the bindingsource, and then acces the original dataset through it. Check out Cp's article on .NET databinding and you should find some usefull stuff.
|
|
|
|
|
I created browser using axWebBrowser.
I want to disable open in new window conmand
and make every link to be opened in main window only.
Is there the way?
|
|
|
|
|
This[^] might help
SkyWalker
|
|
|
|
|
Thanks. That helps a lot.
This means I have to put just AxWebBrowser.Navigate(URL);
in newWindow2,correct?
But How can I get that URL?
Please aid me. I think I'm almost there.
|
|
|
|
|
The url comes as parameter in the event handler. Read it carefully.
SkyWalker
|
|
|
|
|
Wow, I made it. Have to use newWindow3 though^^
Thank you very much.
|
|
|
|
|
hi all,
can anybody lead in how to create a test in VS2005. In breif steps please .
thanks a lot
|
|
|
|
|
what kind of test? Unit test?
|
|
|
|
|
I am not exactly an expert in testing, actually i know nothing about testing.
My application is a windows application that is integrated with an SQL server 2005.
Any more info you need me to tell?
|
|
|
|