yck1509 / ConfuserEx

An open-source, free protector for .NET applications
http://yck1509.github.io/ConfuserEx/
Other
3.57k stars 1.63k forks source link

Exception: System.NotSupportedException: Specified method is not supported #78

Closed kyriacosmichael closed 10 years ago

kyriacosmichael commented 10 years ago

ConfuserEx does not support .NET4.5 ItemContainerTemplate

Steps to reproduce (1). Create an empty WPF 4.5 application.

(2). Add this listbox in MainWindow.xaml

        <ListBox>
            <ListBox.ItemTemplate>
                <ItemContainerTemplate></ItemContainerTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

(3). Try to confuse using

<?xml version="1.0" encoding="utf-8"?>
<project 
    baseDir="C:\Tests\WpfApplication7\bin\Release"
    outputDir="x:\Temp\Confused"
    xmlns="http://confuser.codeplex.com"
    debug="true" 
>
    <rule preset="none" pattern="true">      
        <protection id="ctrl flow" />
    </rule>   
    <module path="WpfApplication7.exe" />
</project>

(4). Error received [ERROR] Unknown error occurred. Exception: System.NotSupportedException: Specified method is not supported. at Confuser.Renamer.BAML.BamlReader.ReadDocument(Stream str) in c:\ConfuserEx-master\Confuser.Renamer\BAML\BamlRW.cs:line 213

at Confuser.Renamer.BAML.BAMLAnalyzer.Analyze(ModuleDefMD module, String baml Name, Byte[] data) in c:\ConfuserEx-master\Confuser.Renamer\BAML\BAMLAnalyzer.cs:line 63

kyriacosmichael commented 10 years ago

I made some investigation on the issue. What I came up with is that if you create the ItemContainerTemplate from code, all is well.

The good news is that you do not need to generate each element in the template by code, but you can generate the whole ItemContainerTemplate from its XAML itself, which is great.

So if you have a listbox with a template like this:

        <ListBox Name="listbox1">
            <ListBox.ItemTemplate>                
                <ItemContainerTemplate>
                    <Label Content="{Binding Name}"></Label>
                </ItemContainerTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

you can convert it at runtime and assign it to the listbox using this code

listbox1.ItemTemplate = XamlDeserialize<ItemContainerTemplate>(@"   
            <ItemContainerTemplate
                xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" 
              xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
                >
                    <Label Content=""{Binding Name}""></Label>
                </ItemContainerTemplate>
             ");

This is the XamlDeserialize method:

  private static T XamlDeserialize<T>(string xamlString)
        {
            var stringReader = new StringReader(xamlString);
            var xmlReader = XmlReader.Create(stringReader);
            return (T)System.Windows.Markup.XamlReader.Load(xmlReader);
        }

This way confuser is very happy confusing the assembly.

If there was a way for confuser to do this on the fly, that would be great.

kyriacosmichael commented 10 years ago

Additionaly info. If your ItemTemplate contains a WPF User Control from the local assembly, you need to add a reference for the user control namespace and the currently executing assembly:

listbox1.ItemTemplate = XamlDeserialize<ItemContainerTemplate>(@"   
            <ItemContainerTemplate
                xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" 
               xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
               xmlns:local=""clr-namespace:WpfApplication7;assembly=WpfApplication7""  
                >
                    <local:UserControl1 />
                </ItemContainerTemplate>
             ");

It is important to reference the local namespace and its assembly. If you simply reference the local namespace

xmlns:local=""clr-namespace:WpfApplication7"" 

it will not work, and will fail with the following error

System.Windows.Markup.XamlReader.Load Cannot create unknown type '{clr-namespace:WpfApplication7}UserControl1'.

Referencing the current executing assembly will help load the loader find the control:

xmlns:local=""clr-namespace:WpfApplication7;assembly=WpfApplication7"" 

To add a user control from a class library in your solution

listbox1.ItemTemplate = XamlDeserialize<ItemContainerTemplate>(@"   
            <ItemContainerTemplate
                xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" 
               xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
               xmlns:classLibrary2=""clr-namespace:ClassLibrary2;assembly=ClassLibrary2"" 
                >
                    <classLibrary2:UserControl7/>
                </ItemContainerTemplate>
             ");