伪破解 componentone silverlight 控件
在silverlight开发中用到了多种控件,有时候现有的控件不能满足要求,于是很多第三方提供了丰富的控件。其中就有componentone,当然要收费,$895。
而如果未注册的话在引用C1控件的时候会在xaml里自动插入C1:C1NagScreen.Nag="True",如:
<C1DateTime:C1DateTimePicker C1:C1NagScreen.Nag="True" />
并最终在程序启动的时候弹出如下界面:
其实别的功能都挺正常,就是这个框比较讨厌,可恶的框框,还好只弹一次。
伪破解只是想办法把这个框给去掉,而不是真正的实现破解注册功能。
用reflector打开C1.Silverlight.dll找到C1NagScreen。见到如下代码:
private static bool AlreadyNagged;
public static readonly DependencyProperty NagProperty;
// Methods
static C1NagScreen()
{
NagProperty = DependencyProperty.RegisterAttached("Nag", typeof(bool), typeof(C1NagScreen), new PropertyMetadata(delegate (DependencyObject s, DependencyPropertyChangedEventArgs e) {
FrameworkElement element = (FrameworkElement) s;
element.Loaded += delegate {
if (!AlreadyNagged)
{
AlreadyNagged = true;
new C1NagScreen().ShowModal();
}
};
}));
}
这就知道为什么虽然引用多个控件的话会多次设置NagProperty,而真正启动的时候也只会弹出一次框框。
多么冲动的想把AlreadyNagged字段设成true,运用反射吧,很不幸的是silverlight的安全机制阻止了我们设置私有字段。
继续往上看,C1NagScreen是继承自C1Window,而ShowModal正是C1Window的方法。
public void ShowModal()
{
this.VerifyCanShow();
if (this._canvas.Children.Contains(this) && (base.Visibility == Visibility.Visible))
{
throw new InvalidOperationException("ShowModal can be called only on hidden windows.");
}
if (!this._canvas.Children.Contains(this))
{
this._canvas.Children.Add(this);
}
VerifyDefaultCanvasInserted();
this._context.ModalWindow.Remove(this);
this._context.ModalWindow.Add(this);
base.TabNavigation = KeyboardNavigationMode.Cycle;
base.Visibility = Visibility.Visible;
if (!base.Focus())
{
base.Loaded += delegate (object s, RoutedEventArgs e) {
base.Focus();
};
}
this.IsActive = true;
this.fixWindowOrder();
this.BringPopupToFront();
}
private void BringPopupToFront()
{
base.Dispatcher.BeginInvoke(delegate {
_contexts[_defaultCanvas].Popup.IsOpen = false;
_contexts[_defaultCanvas].Popup.IsOpen = true;
});
}
仔细分析确定弹出的窗口是个Popup。略有思路,看看能否在popup窗口弹出的瞬间把它关掉。在MainPage中实现下思路:
public MainPage()
{
InitializeComponent();
var timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(1);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
var pops = VisualTreeHelper.GetOpenPopups();
if (pops.Count() > 0)
{
var pop = pops.First();
pop.IsOpen = false;
((DispatcherTimer)sender).Stop();
}
}
成功是成功了,只是会那么闪一下,不爽。继续分析下,怀疑_defaultCanvas有问题,并最终追踪到:
{
InitializeDefaultCanvas();
panel.Children.Add(_defaultCanvas.Parent as UIElement);
}
private static void InitializeDefaultCanvas()
{
if (_defaultCanvas == null)
{
_defaultCanvas = new Canvas();
Context context = new Context();
_contexts[_defaultCanvas] = context;
_defaultCanvas.SetValue(Canvas.ZIndexProperty, -10000);
context.Popup = new Popup { Child = _defaultCanvas, IsOpen = true };
AttachApplicationRoot();
}
}
<UserControl x:Class="SLC1Window.MainPage">
<Grid x:Name="LayoutRoot" Background="White">
<Grid x:Name="popPanel" Visibility="Collapsed"/>
</Grid>
</UserControl>
后台代码如下:
public MainPage()
{
InitializeComponent();
C1Window.AddDefaultPopupToVisualTree(popPanel);
}
很简单是吧,而且的确如愿工作了,窗口不再显示。
不过也有个后遗症,C1MessageBox等弹出窗口以后也显示不出来的。当然,也可以把方法1和2整合起来,合理解决这个问题:
public MainPage()
{
InitializeComponent();
C1Window.AddDefaultPopupToVisualTree(popPanel);
var timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(1);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
var pops = VisualTreeHelper.GetOpenPopups();
if (pops.Count() > 0)
{
var pop = pops.First();
var panel = pop.Child as Panel;
if (panel == null || panel.Children.Count == 0)
return;
var window = panel.Children[0] as C1Window;
if (window == null)
return;
window.IsActive = false;
window.Visibility = Visibility.Collapsed;
pop.IsOpen = false;
popPanel.Visibility = Visibility.Visible;
((DispatcherTimer)sender).Stop();
}
}
这个只是个人的解决方案,主要是讲个思路,希望对遇到同样问题的你有帮助,期待交流。
另外感谢@zhaohua_wang老师的评价,虽然从严格意义上来说,并没有去实现什么破解,发出来只是为了方便大家平常的学习,并无其他目的,如果商用的话还是请大家支持和购买正版。