|
Controls don't have Opacity properties. It applies to the Form, not it's controls. The entire form has to change its opacity, not the controls.
Dave Kreskowiak
Microsoft MVP - Visual Basic
|
|
|
|
|
I want to know which ip/ports(sockets) are currently in use. How can I do that?
Danger!
|
|
|
|
|
|
led mike wrote: Loop and Bind
Oh no! This is not a really applied method! It's too time consuming! Certainly, the OS has a list of ports that are currently in use, or vice versa, a list of available ports. How can I ask the Framework to give me this list?
Danger!
|
|
|
|
|
|
Absolutely Fantastic, Thanks a lot!
Danger!
|
|
|
|
|
I have the same thread in the MSDN forums, but sadly no one has replied so far. I hope that someone can help me out here
Upon invoking a Delegate created from a DynamicMethod, I receive the following error "Common Language Runtime detected an invalid program.".
It's a bit hard to shape the problem verbally, but I'll try my best, since I would need to post a lot of source code - however, here's my got at it:
I have a Method Manager class. This class allows me to story a collection of MethodInfo objects into a Dictionary object, whose key is a Type.
class MethodInfoCollection: List<MethodInfo> { ... }<br />
<br />
Dictionary<Type, MethodInfoCollection> m_Methods; ...etc
Let's say I'd want to call a specific method for each Key of this m_Methods Dictionary. I would iterate into each MethodInfoCollection and then into each MethodInfo object, checking if the names matche, and then executing via Invoke(); . These MethodInfo objects are coming from different objects instances.
CallMethod("Update"); // this calls every "Update" method found in the m_Methods collection.
Since MethodInfo.Invoke() is way much too slow for my needs, I thought I could come up with another method, that is using DynamicMethods.
I already have a List<string> (m_InterfaceMethods ) containing all the possible method names (like "Update" in the above CallMethod call).
My intent is to create a lookup table of Delegates. So, it would be a
delegate void SpecificDelegate();<br />
<br />
Dictionary<string, SpecificDelegate> m_MSILMethods;
- for every known method name, there will be a dynamically created method which in turn will call all the methods - whose names are matching the string Key. I hope this is clear enough.
<code>public static void CallMethod(string MethodName)
{
m_MSILMethods[MethodName].Invoke();
}
</code>
How to create a DynamicMethod which will invoke in its IL a series of methods? Those methods are stored in a MethodInfo class. Which instructions do I require for it to work?
MSIL Method Generator:
<code>DynamicMethod m_MSILMethod;
ILGenerator m_ILGenerator;
foreach (string m_InterfaceMethod in m_InterfaceMethods)
{
[...].
m_MSILMethod = new DynamicMethod(String.Format("Managed{0}", m_InterfaceMethod), null, null, typeof(MyManager));
m_ILGenerator = m_MSILMethod.GetILGenerator();
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_0);
m_ILGenerator.Emit(OpCodes.Call, m_Method);
}
}
}
m_ILGenerator.Emit(OpCodes.Ldnull);
m_ILGenerator.Emit(OpCodes.Ret);
m_MSILMethods.Add(m_InterfaceMethod, (SpecificDelegate)m_MSILMethod.CreateDelegate(typeof(SpecificDelegate)));
}</code>
Looks like the DynamicMethod generator is not working, perhaps a flaw in the MSIL emitted.
It all boils down to this question, perhaps: How to create a DynamicMethod which will invoke in its IL a series of methods? Those methods are stored as MethodInfos. Which instructions do I require for it to work?
Thanks in advance for your time and any help is much appreciated.
|
|
|
|
|
I was able to reproduce your problem and figure out the offending IL statement. It's the m_ILGenerator.Emit(OpCodes.Ldnull); before you emit the ret statement. Let me know if it still reports invalid programs after you removed the statement.
|
|
|
|
|
Thanks, I'll check this as soon as I get home.
Edit:
By removing ldnull I get a unhandled AccessViolationException, exactly where DynamicMethod.Invoke is called.
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Is my idea feasible or perhaps there's something wrong in my dynamic method creation routine? The code above has been stripped and reduced from the original version.
Thanks in advance for any help.
Edit 2: I guess Ldnull is needed since the return value is of type "void".
Those ld_arg0 instructions don't seem correct to me, but then again, I don't know which specific instructions I should call in order to call the methods of the proper objects.
-- modified at 19:13 Friday 12th January, 2007
|
|
|
|
|
Roberto Collina wrote: By removing ldnull I get a unhandled AccessViolationException, exactly where DynamicMethod.Invoke is called.
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
That's a strange error for a managed application. Do any of the invoked methods end up calling unmanaged code?
Roberto Collina wrote:
Edit 2: I guess Ldnull is needed since the return value is of type "void".
No, it's not. Here's the IL dump generated by ildasm for a simple method that prints "Hello" to the console.
.method public hidebysig instance void TestMethod() cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Hello"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
}
You can see that there is no ldnull instruction before the ret statement.
Could you try running the following program? It is the test program I tried for reproducing your problem.
public class Program
{
delegate void MyDelegate();
public void TestMethod(){Console.WriteLine("Hello");}
public static void Main()
{
Program p = new Program();
MethodInfo methodInfo = p.GetType().GetMethod("TestMethod");
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.Ret);
MyDelegate d = (MyDelegate)dynMethod.CreateDelegate(typeof(MyDelegate));
d.Invoke();
}
}
As you can see, it generates DynTestMethod , which simply forwards the call to TestMethod . If this works for you, then you can be sure that the IL generation part is correct.
Also, are any of your MethodInfo's static? If they are, then OpCodes.Ldarg_0 should not be emitted for those methods. That statement is for passing the this parameter and it should not be passed to static methods.
|
|
|
|
|
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
|
|
|
|
|