Posts Tagged ‘winforms’

Rtf2Html 1.22

New stuff:

  • UI tweaks
  • Removal of block indent (where every line is indented) from pasted RTF text
  • Tweaks for better HTML output (e.g. no more useless span tags containing only whitespace)
  • Accurate preview using XULRunner (via GeckoFX); no longer using the stupid .NET WebBrowser control
  • New logo/icon (I just really hated the old one I made and it was bugging the hell out of me)

Rtf2Html logo

Download here
(requires .NET Framework 2.0 or higher)

Rtf2Html screenshot

The app was designed around the goal of being able to quickly copy and paste snippets of code from Visual Studio (or Netbeans) and turning it into HTML that I could embed in these blog posts; this update stays true to that, and that’s why this app is still so sparse on features, such as conversion of font size or paragraph alignment attributes.

The block indentation removal that now occurs after text is pasted in may be a bit slow. Text in the RichTextBox is selected and altered within the text box itself (it’ll also freeze the UI – if you understand multithreading and WinForms, you know why it’s not simply a matter of spawning off a thread). The alternative is to deal with an RTF parser and edit the RTF input directly, but that’s way more work than I’d care to devote to this app at the moment.

Enyo

I missed webOS Developer Day, but I took a look at the presentation of the Enyo framework (video below). I like most of the bullet points: faster performance, hardware acceleration built-in, etc. However, one point that’s troubling me is the idea of using higher-level controls instead of divs. From the bit of code presented in the final demo, it looks like layout (and pretty much all UI stuff) will be done using JavaScript widgets, which are translated at some point into the appropriate HTML constructs. Obviously, widget-centered development isn’t a new concept (MFC, WinForms, Cocoa… sproutcore and such on the web) nor is it necessarily a bad one (getting something presentable up and running is easier), but there always seems to be a very real and very large loss of flexibility.

When a widget doesn’t look or function exactly how you need it to, and it becomes necessary to make a new one, development within the widget framework can range in difficulty from trivial to near-impossible. As I mentioned when I wrote about Adobe Air, HTML/CSS isn’t perfect, but it’s the most flexible layout and styling framework I’ve come across. Abstracting away that flexibility in favor of plug-and-play widgets makes me cringe… it’s a nice idea, it’s a very (object-oriented) developer-ish idea, but it usually comes with a pretty high cost.

From working with both HTML/CSS and WinForms extensively, I’d say the widget-centered framework model used for desktop apps shouldn’t be replicated for web development. In fact, it should be the other way around: the flexibility of a HTML/CSS-esque system should be brought to the desktop.

How this will play out for Enyo, I don’t know. I’m cautiously optimistic. Being a web framework, everything still boils down to HTML and CSS, but it remains to be seen what level of manipulation will be allowed or make sense (in terms of performance, coding difficultly, etc.) at that level.

SmallChange and LargeChange properties of scrollbars

These properties apply to scrollbar controls in WinForms, but the concepts are pretty universal:

  • SmallChange is the change in value that occurs when you click on a scrollbar’s arrows
  • LargeChange is the change in value that occurs when you click on a scrollbar’s track
  • I had some vague ideas on how to set these values, but this MSDN entry confirmed by suspicions that the values should be set relative to size of the container and not the size of the content.

    User interface guidelines suggest that the SmallChange and LargeChange properties are set relative to the size of the view that the user sees, not to the total size including the unseen part. For example, if you have a picture box with scroll bars displaying a large image, the SmallChange and LargeChange properties should be set relative to the size of the picture box, not to the size of the image.

Mono WinForms layout and invalidate issues

Issue 1: Layout of anchored, non-visible control

I had a custom subcontrol anchored left and right within a parent control. The subcontrol was not visible and would only appear when I called a function to make it visible. The parent control had a default width and height, of course, but would be resized as necessary when placed on a form. With Mono, after being placed on a form, the anchoring seems to take effect based on the default dimensions of the control, not the dimensions of it in the form. This, of course, results in the subcontrol being an incorrect size and position.

I haven’t found a solution to this issue as yet.

Issue 2: Repaint after SuspendLayout/ResumeLayout

When adding a number of custom subcontrols (Dock=Top) to a Panel, I called SuspendLayout() before adding them, and called ResumeLayout() after. The height of the controls are adjusted right after they are added to automatically fit a word-wrapped block of text. On Mono, the Panel is never repainted (meaning the custom controls are never repainted either, and its text is not shown).

Calling Refresh() or Invalidate() after ResumeLayout() solves this issue.

Ekkio feed 2.0

A new feed for the Ekkio desktop client. This replaces the flat buttons with hyperlinks, for a more concise and elegant look.

The real challenge here was creating a WinForms controls where text and links could be rendered side-by-side. The standard Label and LinkLabel controls don’t allow for this.

ekkio feed v2

I’ll do writeup and post some code soon on how to make a control like this.

Embedding WebKit in a WinForms application

This is how to embed a WebKit instance within a WinForms application. I promised, a long time ago, to show this, but never got around to it. The process itself is pretty simple, assuming you have WebKit compiled (which can be pretty difficult) because you’ll need to be able to link with the WebKit libraries, specificially: WebKit.lib and WebKitGUID.lib (which, of course, have dependencies on all of the other libraries produced in the compilation). I’m going to be using a older version of WebKit, the same one I played with in my previous blog posts, as I don’t have time to check out the newest version of WebKit. Hopefully, the interfaces are the same or similar and what I’m about to describe here can be adapted easily to work with the latest version.

What we’re going to do is create a CLI wrapper to allow the .Net application to access the native WebKit code. To mix managed and unmanaged code, we’re going to need to create a C++/CLI application. Yes, it is going to be ugly code, but it works and (I think) much simpler than trying to P/Invoke functions in WebKit.dll.

Here’s the wrapper code (I’ve also included a compiled dll in the /Release folder):
WebKitCLIWrapper.dll.zip

WebKitNativeController.h and WebKitNativeController.cpp is adapted from the demo code provided by Apple. WebKitCLIWrapper.h (shown below) is the C++/CLI .NET code that wraps the native controller.

#pragma once

#include
"WebKitNativeController.h"

namespace WebKitCLIWrapper
{
    
using namespace System;
    
using namespace System::Collections;

    
public ref class Wrapper
    {
        
public:
            Wrapper(IntPtr hwnd, String^ htmlContent)
            {
                webKitController =
new WebKitNativeController();

                IntPtr bstrPtr = System::Runtime::InteropServices::Marshal::StringToBSTR(htmlContent);
                webKitController->Init((HWND)(
int)hwnd, (BSTR*)&bstrPtr);
                System::Runtime::InteropServices::Marshal::FreeBSTR(bstrPtr);
            }

            ~Wrapper()
            {
                webKitController->UnInit();
                webKitController->Release();
            }

            
void LoadURL(String^ url)
            {

                IntPtr bstrPtr = System::Runtime::InteropServices::Marshal::StringToBSTR(url);
                webKitController->LoadURL(*((BSTR*)&bstrPtr));
                System::Runtime::InteropServices::Marshal::FreeBSTR(bstrPtr);
            }
            
        
protected:
            WebKitNativeController*        webKitController;
    };
}

Now, we can simply include WebKitCLIWrapper.dll in any .Net project as a reference and access the wrapper to create a WebKit instance. So if your in Visual C#, create a new WinForms app, create a Panel (panel1) on a form, and add the following to the form’s Load event:

WebKitCLIWrapper.Wrapper wrap = new Wrapper(panel1.Handle, "");
wrap.LoadURL(
"http://arstechnica.com/");

However, before running the application, you need all the necessary libraries and necessary resources referenced by WebKit.dll in the app’s working directory (I like to set it to Debug).

For convenience, here’s a zip containing all you’ll need:
WebKit_dlls+resources.zip
(as I mentioned, this is an older version of WebKit)

With all the necessary files in place, launch the app, and a WebKit instance should load in the specified panel (panel1) along with the web page specified in LoadURL() call.

arstechnica.com loaded in a webkit container within a WinForms application

If you’d like to display and process a specific piece of HTML code, get rid of the LoadURL() call, place the code to be embedded in a string, and pass it as the 2nd argument to the WebKitCLIWrapper.Wrapper constructor. For example, this will load and embed a youtube video:

string embed = "<object width=\"425\" height=\"344\"><param name=\"movie\" value=\"http://www.youtube.com/v/SuBqIrgKnNg&hl=en&fs=1\"></param><param name=\"allowFullScreen\" value=\"true\"></param><embed src=\"http://www.youtube.com/v/SuBqIrgKnNg&hl=en&fs=1\" type=\"application/x-shockwave-flash\" allowfullscreen=\"true\" width=\"425\" height=\"344\"></embed></object>";
WebKitCLIWrapper.
Wrapper wrap = new Wrapper(panel1.Handle, embed);

cookie monster npr interview, displayed in a webkit instance with a WinForms panel

The wrapper interface is very bare-bones, but it’s good enough if you just need to display some web or HTML content in your app or, if your looking to build a .NET web browser, it will hopefully provide a starting point for how to interact with WebKit.

User objects

A while back I wrote about 2 applications, The KMPlayer and JCreator not behaving well when attempting to run both concurrently (see post).

Now, I have an incredibly weird situation on my system. KMPlayer and JCreator don’t play nice together. If they’re both open, some JCreator panels and menus are suddenly blank and don’t refresh and the side tabs panel is transparent, showing thru to the desktop. As for KMPlayer, I can’t open anything, clicking play (which plays the last file opened when nothing else has been loaded) does nothing, and certain items are mysteriously missing from the context menu. This hasn’t been a big deal for me, and I still use both JCreator and KMPlayer, but it would be nice if they worked together. Also, I have to wonder, what is the common component causing the conflict here, what would a media player and a java IDE both be using or trying to access concurrently? (assuming there is a conflict for a common component, which I suspect might be the issue here)

My suspicion was wrong, it was not a conflict between the applications or a common component, it was the system running out of User objects. In Winforms (and I suspect most other GUI toolkits as well) any GUI control or window will consume at least 1 user object (more complex controls, with multiple sub-components will consume more User objects), and when the system or process hits the limit (65,536 for the user session, 200 – 18,000 per-process; default is 10,000 on Windows XP), creation of new User objects will fail, even if the system has enough memory to support whatever it is that’s being created. On the .NET Framework, you’ll notice this if you get an exception that looks similar to the following,

System.ComponentModel.Win32Exception: Error creating window handle. at System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp) at System.Windows.Forms.Control.CreateHandle() at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible) at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible) at System.Windows.Forms.Control.CreateControl()

I’m still puzzled as to why there simply isn’t a limit based on available memory, but I haven’t been able to find a whole lot written on User objects in general much less details on why they exist.

Mono Winforms on OS X

Despite some issues, my experience porting .NET C#/Winforms 2.0 code to a Linux system running Mono was surprisingly pleasant. Unfortunately, the same cannot be said for porting to OS X. Put simply, Mono Winforms on OS X sucks… it sucks bad… to the point where I question why it was even released.

fragmentsync mono winforms issues

The biggest and most apparent issues seems to be visibility and z-order issue. The image above is a form containing a few panels, however, only the panel containing the green header and the “sync with” label should the displayed. The others should be invisible (Control.Visible = false). Furthermore, making one control visible and another invisible or bringing a control to the front (Control.BringToFront()) such that it obscures others is a crapshoot; sometimes it’ll work correctly, other times you’ll see the correct control briefly before it disappears and your staring at a control that should be invisible or obscured.

Performance is atrocious. Winforms itself, even under .NET on Windows, is not a terribly high-performance windowing system, but it’s unbearable under OS X, to the point where you can see very prominent visual delays as events are processed and/or controls are being rendered.

Stability is awful. It’s not uncommon to reach a point where the application’s UI simply freezes up and no longer responds to events. Worse yet, disposal of Controls don’t seem to occur properly. I’ve noticed this on dynamically created controls, on a few occasions; clicking a control resulted in a crash because the control had already been disposed, but the control was still, incorrectly, being rendered in the UI and responding to events (hence the crash).

All of these problems seem to point to an issue with Mono’s per-windowing system driver for OS X. The Mono Project Roadmap indicates an upcoming Winforms update for OS X this September with the Mono 2.6 release, hopefully, it’ll address these (and I’m sure other) critical issues, so that Winforms can become truly cross-platform. As of right now, if your looking to use Mono Winforms as a solution for porting to OS X, you’ll likely only be able to pull off a port of the simplest of applications.

On a side note, Cocoa# looks like a pretty interesting project, but the website hasn’t been updated in months, so it’s possible the project is dead.

Miscellaneous Mono and Mono WinForms issues

A few issues I stumbled across as I was working on porting Fragment Sync,

Issue #1: Explicit null second argument with ArrayList.BinarySearch
The second argument is optional and leaving it out should (I assume) be the same as passing null resulting in the method using the object’s CompareTo() method (implemented b/c of required IComparable interface). However, Mono threw an exception: System.ArgumentException : Comparer threw an exception

Issue #2: LinkLabel rendering issues
You can see this in the screenshot from my previous post,

mono winforms linklabel rendering issue

The linklabels at the bottom have their AutoSize properties set to false and their TextAlign properties set to MiddleCenter; the rendering issue is obvious (oddly enough, I noticed when a linklabel is disabled it renders correctly). Setting AutoSize to true and redoing some positioning, I got the following (note that a lot of other things have been fixed here as well focus on the menu at the bottom),

mono winforms linklabel rendering issue 2

I’m still working on this and haven’t really found an optimal or pragmatic solution as yet.

Issue #3: No WYSIWYG for improperly anchored controls
Microsoft .Net Framework seems to be able to display a form as-is despite any sort of improper anchoring which would cause issues when resizing. Mono WinForms seems to behave a bit differently, and the position and layout of these controls are not identical to how they look in the designer. My guess would be that form are loaded differently between the 2 implementations.

Issue #4: Panel anchor issue
In Fragment Sync, there is a panel just above the bottom menu that appears and displays notifications. This panel is anchored to stay just above the bottom menu. For reasons I still haven’t figured out, this panel disappeared (I assumed behind the menu). I fought with this for quite a while, but finally surrendered and simply docked it to the bottom. I’m still not sure exactly what the issue was here and anchoring and docking seems to work fine in other forms and controls.

Issue #5: AutoScaleMode
This is something I never payed attention to, but the Visual Studio designer automatically sets AutoScaleMode to AutoScaleMode.Font for every form or user control created. This can very much screw up positioning and layout of elements, so I set it to AutoScaleMode.None for everything. Fragment Sync doesn’t really concern itself with scaling, so this might not be appropriate for every app. Not that this should be done within the designer, trying to change it after InitializeComponent() is called in the constructor seems to have no effect.

Issue #6: Form icon issue
I mentioned in the previous post about problem with Vista-compatible icons which have an embedded 256×256 png. Rather than muck around in the form designer code this can be addressed in the form constructor after the InitializeComponent() call, as the exception for the problematic icon is thrown when the form is shown not initialized. So simply set this.Icon = null; after InitializeComponent() or set this.Icon to a compatible icon.

Issue #7: Notify icon issue
This is caused by the same problem as above (Vista-compatible icons), but can’t be addressed after InitializeComponent() as the exception is thrown earlier, within InitializeComponent(). The easiest fix to just use another icon with the 256×256 bitmaps removed. You could also muck around in the form designer code and edit the offending line.

That’s it for now. I’m eager to do a OS X compile and run, which I’ll try to do within the week.

First thoughts on porting to Mono

I’ve known about Mono since its inception, but a few months ago I really became interested as support for C# 2.0 and WinForms 2.0 was announced. I played around with some code and was pretty impressed at how easy it was to get stuff compiled and running. This weekend I made a concerted effort to tackle something more complex, getting Fragment Sync compiled and running. I’ve read you can simply use Mono with the managed executable and not have to deal with compiling source code, but Fragment Sync does quite a bit of interop with unmanaged code so that really wasn’t an option.

I first attempted to import all the source files into MonoDevelop (commenting out win32 specific stuff), but this proved problematic when it came to resources. I tried a ton of different things, but could not get MonoDevelop to properly compile in the app’s resources. I then read you can just open the Visual Studio solution with MonoDevelop; this proved to be effortless and resolved the compilation issue with resources.

After a successful compiled, I had some issues getting a window up. There was an issue loading the application icon. This seems to be an issue with using Vista-compatible icons (where the 256×256 sized bitmap, is an embedded png). I changed the icon to null for a few forms to resolve this; which involves the following line in the form designer code:

this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));

The final and most serious issue I encountered was with Fragment Sync’s Rijndael encryption code. You can find the issue described in detail here. Note the issue will pop up when using CryptoStream as well, since CryptoStream simply abstracts the calls to the underlying Transform methods of ICryptoTransform. The trick here is to always check that you can reuse the transform. With Microsoft’s implementation you can, with Mono you can’t. So you have to recreate the transform object.

if (!decryptor.CanReuseTransform)
{
    decryptor = rij.CreateDecryptor();
}

With these issues resolved I could get things up and running.

fragment sync running on mono in opensuse

Obviously things don’t look pretty, but I think this is a good starting point to work from to get Linux support for Fragment Sync.

I should mention I did consider using Gtk# and redoing the Fragment Sync user interfaces, but I found Gtk’s design methodology unbearable… let’s just say I’m not a fan of packing widgets into containers.