February 2003 - Posts

There has been quite an uprising against less-than-full-fidelity RSS feeds -- a.k.a. dotnetweblogs.com's new feature to provide content out of the RSS band, via an optional field.

I am at least one person who asked Scott to add this feature. I plan on using my blog as a miniature online-magazine, full of tips and tricks and code snippets -- some of which may be quite long (several hundred lines).

Well, the first time I did that, I was shocked at how ostentatious my blog entry looked, among all the other modest little blog entries on dotnetweblogs.com's homepage (which contains a "virtualized" blog, composed of the last dozen or so posts).

So I promptly wrote Scott a feature-request email, entitled something like "Help me be more like Don Box!" ;-)

Anyway, I don't see the purpose of RSS as a content-streaming medium. I see RSS as a notification mechanism -- to let folks know that something, somewhere, has happened, or been updated, or whatever. Grab your mouse. Click the link. Or don't.

I just discovered my first use for one of the recently-documented API functions: SHObjectProperties, which displays the shell's friendly property-page dialog, for a file!

http://www.arithex.com/showprops.cs.html

It's a bit odd, even by Microsoft-internal standards: it demands the filename argument be fully-qualified, and it seem to run modeless, yet provide no mechanism for the caller to block until it's been closed.

Yet still, it's a nice feature for administrative/diagnostic tools (like DependencyWalker) to have!

Thanks, DoJ!

In doing a little research on ApplicationContext and NotifyIcon last night, I discovered something odd:  ApplicationContext implements the traditional Finalize/Dispose pattern that we all know and love, but it doesn't actually implement IDisposable.

At first, this seemed like a terrible oversight -- after all, how could the Dispose method ever be called?  So I tacked an IDisposable implementation onto my derived class, and wrapped the scope of my ApplicationContext object in a C# "using" block.  Then I spent a precious few moments patting myself on the back: "I'm such a good software developer."  ;-) 

So, imagine my surprise when I noticed that my cleanup code was being executed twice!  Whaa?

Then I realized how the magic works:  ApplicationContext calls its own Dispose virtual function, within the scope of its own ExitThread(Core) method.  Epiphany:  IDisposable is really just an attribute -- a way for a class to advertise to the outside world that it has some unmanaged resources, and could benefit from being explicitly told when to cleanup.

But ApplicationContext doesn't need to advertise -- it already has to be shutdown explicitly (typically either by closing the main form, or an explicit call to its ExitThread function) so it's perfectly capable of managing its own cleanup, without help from anyone on the outside.

 

Recently, in the halls around my office, I've heard several folks despair
that it's impossible (or requires p/invoking?!) to create a WinForms app
that's initially invisible.

Huh? The following technique works for me, per [1].

[1] http://msdn.microsoft.com/library/en-us/vbcon/html/vbtsksettingformtobeinvisibleatitsinception.asp

In a nutshell, the problem is that the implementation of Application.Run(Form) calls
Form.Show, internally.  "Doc, it hurts when I go like this."  ;-)


using System;

class Form1 : System.Windows.Forms.Form
{
 public Form1()
 {
  this.Size = new System.Drawing.Size(300,300);
  this.Visible = false;
 }

 [STAThread]
 static void Main()
 {
  Form1 f1 = new Form1();
  f1.Text = "This is my form";

  System.Threading.Thread.Sleep(3500);
  // note the form is not visible, and does not
  // appear in the taskbar or alt-tab list, for 3.5
  // seconds

  f1.ShowDialog();
  // alternatively, you can use fl.Show(), along with
  // a separate ApplicationContext object to control
  // the lifetime of the main thread / message pump
 }
}
/*
Build with /target:winexe
*/

Following up on http://dotnetweblogs.com/SAVanNess/archive/02102003.aspx...

...we purportedly wowed a tired, late-evening audience at VSLive, last week:

http://www.leszynski.com/newEvents.htm
http://www.leszynski.com/popVSLive0302.htm

Woohoo!
-S

In my day job, I do a lot of development for the Tablet platform.  This weekend, I accomplished what I think must be a first:  I wrapped one of our proprietary ink-recognition engines with a VS addin, and thus created an "ink-based form designer". 

I was dubious about this little project, when I started -- but in the end, I was actually surprised by how easy and intuitive it was to just draw the layout of controls on a form.  I mean, it's something we're all used to doing, on a whiteboard!

Mind you, the screens and keyboards (and chips) are all way too small on today's tablets to consider running VS.NET, productively.  But in the future, there's a very good chance that many LCD flat panel screens will have little pens attached... as an alternative to the mouse, not a replacement.

Anyway, after we demo this technology at VSLive this week, I will post a screenshot or two.  It's pretty fly, and I'm quite proud.  The coolest part is, now that our patented reco technology is nearing completion, the hardest part was getting VS.NET installed on a bloody tablet...  ;-)

 

I discovered the [ComRegisterFunction] attribute, last night...  I think I always knew about it, but I'd forgotten.  It beats the heck out of shipping a .reg file alongside one's addin, like all the VS addin samples on MSDN seem to like to do...

Then, to help drive the installation for this little demo I'm working on, I wrote a two-line Setup.exe in C# that calls RegistrationServices.RegisterAssembly (the programmatic equivalent to the command line's regasm.exe).

.NET is just too groovy.  Anyway, watch for us on-stage at VSLive, sometime late Wednesday evening, where we'll give a glimpse of what visual form-design will be like in the future...

-S

using System;
using System.Runtime.InteropServices;

using Extensibility;
using EnvDTE;
using Microsoft.Office.Core;

namespace Leszynski.Ink.VisualStudio
{
    [GuidAttribute("1F2A0E29-1934-4E2F-8E25-89467D68F3A9"), ProgId("Leszynski.InSpireAddin")]
    public class InSpireAddin : IDTExtensibility2
    {
        // Construction
        //
        public InSpireAddin() // public default ctor to suppt COM activation
        { }

        // Custom COM registration
        //
        [ComRegisterFunction]
        public static void CustomRegister(Type t)
        {
            Microsoft.Win32.RegistryKey rk = 
                Microsoft.Win32.Registry.CurrentUser.OpenSubKey( @"Software\Microsoft\VisualStudio\7.0\AddIns"true);
            rk = rk.CreateSubKey( "Leszynski.InSpireAddin");
            rk.SetValue( "FriendlyName""Leszynski inSpire Form Designer");
            rk.SetValue( "Description""Ink-based Collaborative Form Designer");
        }

        [ComUnregisterFunction]
        public static void CustomUnregister(Type t)
        {
            Microsoft.Win32.RegistryKey rk = 
                Microsoft.Win32.Registry.CurrentUser.OpenSubKey( @"Software\Microsoft\VisualStudio\7.0\AddIns"true);
            rk.DeleteSubKeyTree( "Leszynski.InSpireAddin");
        }

        // IDTExtensibility2 implementation
        //...

Since the advent of .NET, COM has been getting nothing but bad press, primarily regarding its lack of full-fidelity type information, and poor cross-language interoperability.

I agree that COM was broken because it lacked full-fidelity type information -- but its type-info woes would have been easy to solve.  In fact,  I often wonder why MS (or maybe even some 3rd party) never replaced IDL with an XML grammar to describe interfaces, their methods, and parameters...  and replaced oleaut32.dll with a new universal marshalling engine based on that XML grammar.  Heck, I almost did that myself, one rainy weekend...

(For the record, I think the problem was VB's inability to interoperate w/ COM's datatypes, not the other way around.)

MS didn't spend billions on .NET just to fix type-info, or to run Java out of business.  .NET is here today because the opportunity existed to knock off many other COM/C++ problems with the same stone:  a managed execution environment to avoid buffer overruns, a gc'd heap to avoid leaks, a loader to support sxs versioning, a virtualized instruction set to run code natively on Pentium/Itanium/Hammer/Transmeta/Whatever, a sandbox in which to run untrusted code, ...  and last but not least, full-fidelity type info to facilitate communication across module, language, and security boundaries.

-S

More Posts