How to hook up EventHandler or Delegate to UserControl thru Reflec

S

sippyuconn

Hi

I have an Assembly that has various usercontrols that all implemnet
an Interface

The Interface

public interface ISettings
{
bool SaveSettings();
}


I then have a test pgm that will loop thru the asssmbly and find all classes
that implement the ISettings interface. I then display all the UserControls
on a Form

Assembly asm = Assembly.LoadFrom(@"C:\myUserContro.dll");
// Walk through each type in the assembly looking for our
class
foreach (Type type in asm.GetTypes())
{
if (type.IsClass == true )
{
bClass = false;
foreach (Type interfaceType in type.GetInterfaces())
{
if (interfaceType.FullName.Contains("ISettings"))
{
bClass = true;
break;
}
}

if(bClass)
{
Control control = Activator.CreateInstance(type)
as Control;
xtraTabControl1.TabPages.Add();

xtraTabControl1.TabPages[xtraTabControl1.TabPages.Count - 1].Text =
type.FullName;

xtraTabControl1.TabPages[xtraTabControl1.TabPages.Count-1].Controls.Add(control);


}
}


This is all fine
The question is on the form where I create the UserControls I have a "SAVE"
button. When I hit the SAVE button I want to fire all the interface method
"SaveSettings" from all the UserControls.

What is the best way to do that???

Thanks
 
R

raylopez99

On Thu, 04 Sep 2008 14:21:01 -0700, sippyuconn  
I don't think reflection as anything to do with the question.  As far as  
what's the "best way", that's not for us to say.  But one option might be  
to create a delegate and add the SaveSettings() method for each  
implementor to the delegate.  For example:
Of course, it begs the question as to why the method returns a bool.  If  
you actually want to use that in some way, you'll want to change the  
invocation.  For example:

yeah I guess I second Peter on this. I find that a delegate is like a
super "GOTO" statement, that you can 'throw' to call another function
that's not even aware of what's going on in the code that throws. A
global GOTO.

The other option, equally bad but easier to write, is of course to use
the old standby of a 'global' boolean (to the namespace, as C# has no
true global variables). When the global boolean is changed, an if
statement somewhere in your active code takes over. And of course the
related solution of using enums and case statements, which is how
classic Windows works.

I think the problem though is that in C# Winforms code and data and
not separated. I'm looking forward to studying WPF in a few months
and seeing how they supposedly solved the problem by separating code
and data.

RL
 
S

sippyuconn

I mention reflection because the interface is in a third party assemble that
I don't have access to code so I needed to use reflection to get at the
interface and Method

But I am stuck - how to tie the Class or Methods of Class using relection to
extract - to then tie to Delegate


public delegate bool CustomSaveHandler();


Assembly asm = Assembly.LoadFrom(@"C:\myassembly.dll");
// Walk through each type in the assembly looking for our
class
foreach (Type type in asm.GetTypes())
{
if (type.IsClass == true )
{
bClass = false;
foreach (Type interfaceType in type.GetInterfaces())
{
if (interfaceType.FullName.Contains("ISettings"))
{
bClass = true;
break;
}
}

if(bClass)
{
Control control = Activator.CreateInstance(type)
as Control;
xtraTabControl1.TabPages.Add();

xtraTabControl1.TabPages[xtraTabControl1.TabPages.Count - 1].Text =
type.FullName;

xtraTabControl1.TabPages[xtraTabControl1.TabPages.Count-1].Controls.Add(control);

MethodInfo typemethod =
type.GetMethod("SaveSettings");

?????
 
Z

Zhi-Xin Ye [MSFT]

Dear sippyuconn,

You can call the Type.GetInterface() method to retrieve the interface, and
call Type.GetMethod() method to retrieve the "SaveSettings" method, then
call the Invoke() method to invoke the "SaveSettings" method.

For example, you can do something like this(I use a List<Control>
collection to store the UserControls in this example):

List<Control> ctlsFromAsm = new List<Control>();

private void button1_Click(object sender, EventArgs e)
{
foreach (Control c in this.ctlsFromAsm)
{

c.GetType().GetInterface("ISettings").GetMethod("SaveSettings").Invoke(c,
null);
}
}

If any of this is unclear, please feel free to let me know.

Sincerely,
Zhi-Xin Ye
Microsoft Managed Newsgroup Support Team

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://support.microsoft.com/select/default.aspx?target=assistance&ln=en-us.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
R

raylopez99

Reading these replies makes me wonder: is it possible to use
reflection to extract methods from .exe files? Not .DLL but
executables? I doubt it, because it would defeat the purpose of the
obfuscator, and/or why people distribute binary rather than source
code (to protect the IP in the source code), but I could be wrong.

Just curious.

RL
 
J

Jon Skeet [C# MVP]

Reading these replies makes me wonder:  is it possible to use
reflection to extract methods from .exe files?
Yes.

 Not .DLL but executables?  I doubt it, because it would defeat the purpose of the
obfuscator, and/or why people distribute binary rather than source
code (to protect the IP in the source code), but I could be wrong.

Not everyone wants to have to compile code before using it. Note that
using reflection to find methods isn't the same as decompilation,
although both are feasible on executables. Download RedGate Reflector
and have a look.

http://www.red-gate.com/products/reflector/

Jon
 
P

Pavel Minaev

raylopez99 said:
Reading these replies makes me wonder: is it possible to use
reflection to extract methods from .exe files? Not .DLL but
executables? I doubt it, because it would defeat the purpose of the
obfuscator, and/or why people distribute binary rather than source
code (to protect the IP in the source code), but I could be wrong.

For the record, there isn't much difference between .NET .exe and .dll
assemblies. For example, you can actually reference an .exe assembly from a
project as if it were a .dll library, and use the public classes/methods
within it as usual.
 
S

sippyuconn

This is where my problem is - I cannot cast the Method because it is a
ThirdParty Assemble


public delegate bool CustomSaveHandler();
....

MethodInfo typemethod = type.GetMethod("SaveSettings");

I am trying to add the method to delegate by
but won't compile
Error 3 'typemethod' is a 'variable' but is used like a 'method'


CustomSaveHandler a = new CustomSaveHandler(typemethod);

or

CustomSaveHandler b;
b += new CustomSaveHandler(typemethod);



What is the way around this if I cannot cast the method ???

Thanks
 
J

Jon Skeet [C# MVP]

This is where my problem is - I cannot cast the Method because it is a
ThirdParty Assemble

public delegate bool CustomSaveHandler();
...

 MethodInfo typemethod = type.GetMethod("SaveSettings");

I am trying to add the method to delegate by
but won't compile
Error   3       'typemethod' is a 'variable' but is used like a 'method'        

CustomSaveHandler a = new CustomSaveHandler(typemethod);

or

CustomSaveHandler b;
b += new CustomSaveHandler(typemethod);

What is the way around this if I cannot cast the method ???

Use

b += (CustomSaveHandler)
Delegate.CreateDelegate(typeof(CustomSaveHandler), typemethod);

Jon
 
S

sippyuconn

public delegate bool CustomSaveHandler();

public partial class Form1 : Form
{



public Form1()
{
InitializeComponent();
LoadConfigurationUserControls();

}

private void LoadConfigurationUserControls()
{
bool bClass = false;

CustomSaveHandler a = null;


List<string> list = new List<string>();
try
{
Assembly asm = Assembly.LoadFrom(@"C:\Mydll.dll");
// Walk through each type in the assembly looking for our
class
foreach (Type type in asm.GetTypes())
{
if (type.IsClass == true )
{
bClass = false;
foreach (Type interfaceType in type.GetInterfaces())
{
if (interfaceType.FullName.Contains("ISettings"))
{
bClass = true;
break;
}
}

if(bClass)
{
Control control = Activator.CreateInstance(type)
as Control;
xtraTabControl1.TabPages.Add();

xtraTabControl1.TabPages[xtraTabControl1.TabPages.Count - 1].Text =
type.FullName;

xtraTabControl1.TabPages[xtraTabControl1.TabPages.Count-1].Controls.Add(control);

MethodInfo typemethod =
type.GetMethod("SaveSettings");



a +=
(CustomSaveHandler)Delegate.CreateDelegate(typeof(CustomSaveHandler),
typemethod);

}
}
}
 
J

Jon Skeet [C# MVP]

public delegate bool CustomSaveHandler();

public partial class Form1 : Form

<snip>

Okay, well that's not a *complete* example because you've only posted
half of the form's code. By the time you've made it complete it then
won't be short, because you're using a GUI for no particular reason.
Furthermore, you're loading an assembly we haven't got, so we can't
possibly test it.

Given the code you've actually written, however, here's the short but
complete code which would have saved me some time and immediately
given me code I could compile, run and fix:

using System;
using System.Reflection;

public class Settings
{
public bool SaveSettings()
{
Console.WriteLine("Called");
return true;
}
}

public delegate bool CustomSaveHandler();

public class Test
{
static void Main()
{
// Fetched dynamically in real code
Type clazz = typeof(Settings);
object instance = Activator.CreateInstance(clazz);
MethodInfo method = clazz.GetMethod("SaveSettings");

// This line throws an exception
CustomSaveHandler handler = (CustomSaveHandler)
Delegate.CreateDelegate(typeof(CustomSaveHandler),
method);

handler();
}
}

The fix is quite simple - you need a different overload for
CreateDelegate: the one which takes the target of the call as well:

CustomSaveHandler handler = (CustomSaveHandler)
Delegate.CreateDelegate(typeof(CustomSaveHandler),
instance, method);

Hope this helps - and please bear in mind the hints above next time
you want to demonstrate a problem on newsgroups.

Jon
 
R

raylopez99

For the record, there isn't much difference between .NET .exe and .dll
assemblies. For example, you can actually reference an .exe assembly froma
project as if it were a .dll library, and use the public classes/methods
within it as usual.


Thanks, that was interesting. From Jon's link I see that the tool at
RedGate assumes you do not use the 'obfuscator', otherwise, they would
not mention it (see %%% below).

From this I conclude that when in non-release, non-obfuscated code,
your .exe file is like a .dll file for .NET assemblies--I did not know
that.

RL


Use Reflector if you need to:

* Explore .NET assemblies in an easy-to-understand, natural way
* Understand the relationships between classes and methods
* Find where types are instantiated and exposed
%%% * Check that your code has been correctly obfuscated before
release %%% //so obfuscation will hide your code from this tool
 
S

sippyuconn

Here is a complete sample



public interface ISettings
{
bool IsDirty { get; }
bool SaveSettings();
bool LoadSettings();
}



public partial class UserControl1 : UserControl, ISettings
{
private bool isdirty;
public bool IsDirty
{
get { return (isdirty);}
set { isdirty = value;}
}

//Commits all changes for all tabs to the database, true if success,
false if failure
public bool SaveSettings()
{
bool bRet = false;

return (bRet);
}

//Commits all changes for all tabs to the database, true if success,
false if failure
public bool LoadSettings()
{
bool bRet = true;

return (bRet);
}

public UserControl1()
{
InitializeComponent();
}
}







public delegate bool CustomSaveHandler();

public partial class Form1 : Form
{



public Form1()
{
InitializeComponent();
LoadConfigurationUserControls();

}

private void LoadConfigurationUserControls()
{
bool bClass = false;

CustomSaveHandler a = null;


List<string> list = new List<string>();
try
{
Assembly asm = Assembly.LoadFrom(@"C:\Mydll.dll");
// Walk through each type in the assembly looking for our
class
foreach (Type type in asm.GetTypes())
{
if (type.IsClass == true )
{
bClass = false;
foreach (Type interfaceType in type.GetInterfaces())
{
if (interfaceType.FullName.Contains("ISettings"))
{
bClass = true;
break;
}
}

if(bClass)
{
Control control = Activator.CreateInstance(type)
as Control;
xtraTabControl1.TabPages.Add();

xtraTabControl1.TabPages[xtraTabControl1.TabPages.Count - 1].Text =
type.FullName;

xtraTabControl1.TabPages[xtraTabControl1.TabPages.Count-1].Controls.Add(control);

MethodInfo typemethod =
type.GetMethod("SaveSettings");



a +=
(CustomSaveHandler)Delegate.CreateDelegate(typeof(CustomSaveHandler),
typemethod);

}
}
}
 
P

Pavel Minaev

Thanks, that was interesting. From Jon's link I see that the tool at
RedGate assumes you do not use the 'obfuscator', otherwise, they would
not mention it (see %%% below).

Well yes. The point of obfuscators is to make decompiled code unreadable.
Note that you can still decompile the code, and you can still reference the
obfuscated .exe/.dll and call the public methods within, though. Obfuscators
will typically mangle internal & private member identifiers within the
assembly so that they are unreadable, and rearrange IL so that tools like
Reflector will have a hard time to tell that something is a for-loop, for
example, and will instead decompile to a mess of if-else-goto. But
technically, even such obfuscated decompiled code fully captures the logic
of the algorithm, it's just very hard to read.
From this I conclude that when in non-release, non-obfuscated code,
your .exe file is like a .dll file for .NET assemblies--I did not know
that.

Debug/Release is absolutely irrelevant here - it only concerns IL
optimizations. An assembly is still an assembly in either of those modes.
Regarding obfuscation, see above.
 
R

raylopez99

Well yes. The point of obfuscators is to make decompiled code unreadable.
Note that you can still decompile the code, and you can still reference the
obfuscated .exe/.dll and call the public methods within, though.
But technically, even such obfuscated decompiled code fully captures the logic
of the algorithm, it's just very hard to read.

Well that's interesting. So you are saying a Reflector can still call
on the public methods of obfuscated code--it's the internal structure
of the methods that is scrambled. Very interesting.

RL
 
R

raylopez99

You may benefit from reading:
   http://www.excelsior-usa.com/articles/java-obfuscators.html

(it is about Java, but you can more or less replace all occurrences
of "Java" with "C#")


Thanks. I read it, and don't believe it. I find this particularly
hard to believe:

/*
Impact of Flow Obfuscation on Performance

You may now wonder what might be the degree of impact of such
extensive transformations on application performance. So did I,
therefore my next step was running a well-known benchmark suite
through JBCO.

The slowdown ranges from 3.3x for the Monte Carlo test to over 30x for
SOR and LU. The composite score is 22.8x lower for the obfuscated
version!
*/

I can't believe an obfuscator, which is simply affecting the human
readable source code and should not affect the machine code, would
slowdown something even 3%, much less 3.3x to 30x. Something's not
right.

RL
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top