A lull…

24 07 2008

As projects wind down, it’s been quite the administrative lull lately.  Projects are done and rolling out the door; paperwork is ramped up and covering my desk. :(  Hopefully, over the next few weeks, some new fun and excitement will jump in the door—including a new project involving mobile devices (yay!).

If not, maybe it’ll give me time to get back into experiment mode and kick around the new ASP.NET MVC Preview 4 and ASP.NET AJAX 4.0 Preview.  I haven’t had nearly enough time to dink at home—all this newfound housework takes a LOT of time and energy. Heh.





Search Commands for Office 2007 - GREAT!

5 05 2008

I’ve been using Office 2007 for, well, almost forever.  Compared to the prior versions of Office, it’s better than expected—and quite a dynamic change.  By that, I mean the ribbon toolbar. 

I understand Microsoft’s UI “goodness” and some of the ribbon logic—especially on smaller applications, but the ribbon is still painful to use in huge rambling applications like Microsoft Word and Excel.  I still, after all this time, spend time going, “where the heck is {command}?”

Most of the time, I fall back to using old Office commands that, thankfully, still work.  Other times, it’s an adventure!

That adventurous spirit, however, isn’t shared by every user of Office 2007.  The learning curve of the ribbon and other Office 2007 features has been the leading reason why the latest application suite is still frowned upon in our organization.  Face it—the UI for Word looked the same from about Word 6.0 to 2003.  In one version, that’s a lot of users to reeducate.

To ease those users along and empower the “power” users of Office products, the Office Labs team has released a sweet plugin for Microsoft Office 2007–-Search Commands.  Search Commands is exactly what it says, rather than wading through the half-dozen menus, you enter what you want to do in the search box and the ribbon automagically builds for you.

I’ve been using it for a week or so now, since it came out on 23 April, and love it.  Once you get the Search Commands hot keys down (Alt-Y, E and Alt-Y, 1–9) you can wiz through commands.





Gmail - Odd Filtering Request…

27 03 2008

I love Gmail—in my Archives, I still have my “Welcome!” email (because, I wanted to “save it all” since I had unlimited space) dated back to August ‘04 and I haven’t looked back since. 

It’s fast, has a great interface, and has become recognized and supported by dozens of vendors.  It’s also available EVERYWHERE—home, work, on the road, my cell phone, wireless devices, just everywhere.  I don’t have to worry about syncronizing and it connects to GoogleDocs, Calendar, and the other services extremely well.  If I could find a good way (without a client) to sync my cell phone to Google Calendar, I’d happily kick Exchange to the curb (for personal stuff).

I’m on several mailing lists too… various ones for both work and personal such as altdotnet.  As these groups have grown and conversation sometimes staggers, Gmail has been my saving grace by automagically keeping the hierarchy in a single “thread” to make the conversations easy to follow.

Unfortunately, Gmail can’t “autoforward” to folders—because there are no folders.  Labels and filters are great, but if I go a few hours without reading my email (you laugh… but seriously), I find I have 200+ in my box and can’t see the “real” mail from the list servers.

If I was using Outlook, I’d autoforward emails to a folder and be happy.

So, to get around this with Gmail, I tried something and over the next few days, I’ll see how it works.

  1. Setup a new filter that matches a common criterium of all the emails on a particular list, e.g. all altdotnet emails come from altdotnet@yahoogroups.com.
  2. Next, select “Apply the label” and create a new label for the group AND select “Skip the inbox”. 
  3. Save/Update the filter and, optionally, apply it to the discovered conversations (recommended to be sure you don’t have strays).

Gmail Labels

This applies a label, which is clickable from the Labels section on the left AND gets them out of the inbox, leaving it tidy.  You can see below, at a quick glance, that I have 41 unread “threads” in altdotnet and no outstanding jotts (I <3 Jott).

You also can create hyperlinks DIRECTLY to the individual labels (if you wanted to add them to your favorites, etc) by adding #label/{label name} to the end of your google mail URL. Here’s an example:

http://mail.google.com/#label/altdotnet

Since I use the Google Homepage and Gmail web part, I have a little list of links as well and have added this in there for “quick access” to that label.

Give it a try for a few days and see how it works—hopefully it’ll help tame my information overloaded inbox.





Pipe.Capacity == false || Pipe.ConnectionsTo(’NetFlix’) > this

26 02 2008

<rant>

A need came up today to test how Windows Server 2008 and some of our web apps handled.  Republishing apps is pretty easy given their portability with the Deployment Packages, but simply getting the server going was a pain.  Hardware shortage?  Nah.  Lack of a pipe—heck yeah.

The Pacific through a Straw

I wonder if I can claim any sort of overtime for 352 hours…

We’ve been having huge internet bandwidth issues lately at work—our 100 MB pipe feels like the Pacific Ocean through a straw.  I can usually deal with slow internet browsing (since most sites and services are blocked anyway), but when i need an ISO from Microsoft’s MSDN library, I usually need it right awayish.  *sigh*

The fix?

Last time, the following resolved the problem: remoting into my home computer, starting the download, waiting 5 minutes while it downloaded at 2.8–3.2MB/sec, calling home and asking REALLY nicely for someone to put a DVD in the drive, setting it to burn, driving home (1+ hour), getting DVD, eating lunch, driving back (1+ hour).

Unfortunately, it’s a bit late in the day now—I’ll just do my testing tomorrow.

And that’s acceptable as a “way of doing business.” :(  It could drive a person crazy.  Honestly, while the field trip opportunity is nice, I’d rather things just worked here.

</rant>

 





Snow Day…

31 01 2008

Working in education, there are advantages—one of those being snow days.  Unfortunately, on the days that the 1 ton buses can’t make it through the snow, they feel that our little cars and trucks can and should.

wtf.  :(

Here’s the view outside my office—as of about 8:00am.  We haven’t had as much in town as where I live east (my hour commute was near two today), but it’s still coming down.

Snow

Seriously, I’m ready for global warming.





MOSS 2007 and Wishing I Was “In the Know”

17 01 2008

A rant in the joys of communication and Microsoft Office SharePoint Server 2007 configuration.

It was determined that SSP (Shared Services Providers) would run internally on 8081.  We were told nothing ran on that port in our enterprise.  After FAR too much time (not going to say for sake of my ego) fiddling with why I couldn’t get the SSP services to work in MOSS 2007.

We were lied to like the step-children we are…

After finally just hitting the root of the URL (/ssp/admin/ is the default shortcut), I discovered one of our enterprise “monitoring” softwares had a web service running on that port… which means it’s running on that port on every server and desktop in our enterprise.  wtf.  Oh, and the people who were “in the know”… knew, but didn’t feel it was important or whatever to tell us.

So, now the joys of ripping the SSP out of MOSS and reconfigure it on a different port (and praying THAT one isn’t taken).

*grumbles*

On a side note, I’ll have a new article posted up pretty soon.  The article goes into a bit of detail on setting on a small server farm with MOSS—everything from initial installation to setting up Active Directory profiles, search services, indexing, and updating to the latest Service Pack 1.  After the past week of dinking with this, I now see why Bill English’s MOSS 2007 Administrator’s Guide is 1155 pages and heavy enough to beat someone with.  Good book, by the way—just a bit difficult to follow as there’s no “order” to it.

[UPDATE: While out scraping ice off my car, I had an idea to help myself be more “in the know”.  I use TCPView quite often to see what processes are going where—well, TCPView shows the ports! Just do a bit of monitoring, see where different services are, and go for it.  The fancy alternative, of course, could be to setup Ethereal, set a filter for “tcp.port == {your port here}” and let it run for a day or so.]





Using Reflection rather than PL/SQL…

16 01 2008

Our primary domain database, our student information system, is a packaged solution that sits on top of a huge Oracle database of hundreds of tables, strange naming conventions, and other pains. 

For me to open up SQLPlus and query up a record, like a student, and see what grade their in, who their teacher is, etc. is very time consuming (there are no stored procedures for such queries and I have no access to add them).  :( 

Because of that, and to keep with standards, I created a framework library that is used by all of .NET applications—it handles the database calls, queries, and returns.  It’s further simplified by that the library can only read from the system.

So, I found myself today, on the phone with a customer… trying to look up their class roster.  This requires fetching their SSN (I loathe asking for it), querying their teacher ID from that, doing a look up across about 8 tables to find their classes, schools, class lists, and student records—just to print a list of student names.

After finding what I needed, I finished with the call and sat trying to figure out how I could use .NET and the library for a better way—everything I need exists in our student domain objects.  I just need a quick way to get to them and their properties!

Using Will’s addiction to Reflection as motivation, I ended up with:

Student student = Student.GetStudentByStudentId(123456789);

 

foreach (PropertyInfo prop in

student.GetType().GetProperties().OrderBy(i => i.Name))

{

Console.WriteLine(“{0}\t{1}”,

prop.Name,

prop.GetValue(student, null));

}

The extension method of OrderBy is a nice touch—putting the property bag into alphabetical order and making it easier to read.

The end result looks like (given no data because… well, that’d just be bad):

The final touch was to remove the actual student Id and turn this into a “real” command line application.  I updated the parameter for GetStudentByStudentId to grab the first argument passed to it; and added some help if the argument is missing or incorrect. 

if (args.Count() > 0)

{

Student student = Student.GetStudentByStudentId(int.Parse(args[0]));

}

else

{

Console.WriteLine(“eSIS Query Tool usage: “);

       Console.WriteLine(“\tesisquerytool.exe {studentId}”);

}

It’s REALLY basic, lacks proper column formatting (something I may fix), but REALLY helpful when someone calls me up.  I realize the Oracle and Database gurus will be beside themselves by the fact that I’d rather write a .NET program than query the database directly, but IMHO, part of being a developer is also seeing the tradeoffs.  I can’t “fix” the database design, make it easier, etc.—but I can write a quick little tool to help me on the off chance someone calls and needs an answer. Isn’t that what it’s all about?





A word of warning… your domain is your life!

14 01 2008

Thankfully, our domain names and registrations don’t fall under my “responsibilities,” so I’m still employed.  Others may not be so lucky by the end of the day.

I noticed early this morning—I couldn’t access OWA (Outlook Web Access).  After 10–15 minutes of 404 errors, I gave up and came into work.  When I got into the office, it appeared that all external services were down.  Our public web presence, Lyris server, all external applications facing our customers, VPN services, the works.

After three hours of watching people running around like headless chickens, the truth came out.

No one paid our domain renewal bill—our domain expired:D

I’m assuming that the problem is fixed by now and replication is taking it’s course—but the flood of customer complaints, city advocates calling wondering what’s going on and why we’re “for sale,” and the entire enterprise wondering why external email isn’t working is keeping our Customer Service department hopping.

So, a word of warning—when your registrar sends you the 30 day notice, don’t DELETE it. It’s important and your job SHOULD count on it.

Ahh, Happy Monday.





Flash and Proxy Support on .NET WebBrowser Controls - Part II

4 01 2008

Yesterday, I created a quick Windows Forms application that used an “EnhancedWebBrowser” control to render Flash content and accept proxy server settings on the fly.  As promised, I separated out the control from the project and placed the responsibility for controlling proxy settings back onto the browser control.

If you haven’t read Part I, please do so; it’ll provide the “storyline” for the project. :)

Download the Source Code: .NET 3.5

The source code download includes three projects: the EnhancedWebBrowser forms control, Pandora’s Proxy, my “example” project for using Pandora Music Service and the EnhancedWebBrowser, and the setup project for Pandora’s Proxy—since it’s a Windows Forms app.

Note: This project is for demonstration purposes only and does not represent functionality of Pandora or the Music Genome Project.

Extracting the EnhancedWebBrowser (EWB) Control

The “FlashWebBrowser” control name is a bit obsolete now that it does more than that (with proxy support)… a good test of how important object naming can be.  I’m sure, down the road, I may regret EnhancedWebBrowser, but for demo purposes, it works. :)

Our override of WndProc from yesterday is about the only change that remains of our EWB control—to pull off proxy support in the custom control, we’ll need a public property, another override, and some major changes to our RefreshIESettings method.

Let’s start with our public property.  Since we’re developing in .NET 3.5, we’ll use one of the more useful features: automatic properties.

[Description("Gets or sets the proxy server and port for this instance of the WebBrowser control.  Should be in the format of server:port.")]

public string ProxyServer { get; set; }

That’s easy enough.

Our next step is to set the proxy server settings on the WebBrowser control.  Yesterday, we called this as part of the Load method—which simply applied the settings prior to the WebBrowser.Navigate call.  Since we’re baking this functionality INTO the WebBrowser, we have a bit more control now and can inject the logic directly into Navigate.  This is done by overriding the OnNavigating method.

protected override void OnNavigating(WebBrowserNavigatingEventArgs e)

{

SetProxyServer(ProxyServer);

       base.OnNavigating(e);

}

The new method (well, renamed method) for setting our proxy settings is SetProxyServer.  I could refactor out everything and simply get back to the basics of SetInternetSettings or something, but I’ll leave that as a TODO at this point.

public void SetProxyServer(string proxyServerAddress)

{

const int INTERNET_OPTION_PROXY = 38;

       const int INTERNET_OPEN_TYPE_PROXY = 3;

       const int INTERNET_OPEN_TYPE_DIRECT = 1;

 

INTERNET_PROXY_INFO struct_IPI;

In the first few lines, you’ll notice a new constant, INTERNET_OPEN_TYPE_DIRECT.  Our old method could set the proxy, but couldn’t “unset” or disable it.  This constant allows us the option to disable the proxy settings if so desired.  We’ll use this later on.

// Filling in structure

if (proxyServerAddress == “”)

{

       // Clear any proxy settings and go “direct” to the Internet.

struct_IPI.dwAccessType = INTERNET_OPEN_TYPE_DIRECT;

       struct_IPI.proxy = IntPtr.Zero;

       struct_IPI.proxyBypass = IntPtr.Zero;

}

else

      

       // Assign the specified proxy server and port to

// access the Internet. This supports only

// anonymous proxy servers; support for authentication

// coming in the future.

       struct_IPI.dwAccessType = INTERNET_OPEN_TYPE_PROXY;

       struct_IPI.proxy = Marshal.StringToHGlobalAnsi(proxyServerAddress);

       struct_IPI.proxyBypass = Marshal.StringToHGlobalAnsi(“local”);

}

 

 

Following our constants, we have our logic that toggles the proxy settings on and off.  I kept the comments in the code to clarify what is occuring.

 

// Allocating memory

IntPtr intptrStruct =

Marshal.AllocCoTaskMem(Marshal.SizeOf(struct_IPI));

 

// Converting structure to IntPtr

Marshal.StructureToPtr(struct_IPI, intptrStruct, true);

 

bool iReturn = InternetSetOption(IntPtr.Zero,

INTERNET_OPTION_PROXY,

intptrStruct,

Marshal.SizeOf(struct_IPI));

}

The remaining code (above) remains the same, as does our output.  A quick way to verify is to set a breakpoint at the iReturn—if iReturn is true, then the settings were applied successfully; false then an error occured.

 

That’s it!  That pulls the EWB control out of our project and into a library of its own and adds the proxy support directly into the object.

 

Using the EnhancedWebBrowser

 

After adding a reference to our new library and a quick using statement, we’re ready to start using our EWB.  The only line of code that we need to change is our private variable—the FlashWebBrowser should be EnhancedWebBrowser.

 

private EnhancedWebBrowser enhancedBrowser = new EnhancedWebBrowser();

At this point, you have two options: you can manually assign the EWB control a proxy server with:

 

enhancedBrowser.ProxyServer = “myproxy.server:81″;

or, what I did with the Pandora’s Proxy application, place the proxy settings in the User Settings—allowing the user to control the proxy setting.  Since .NET 2.0, user and application settings are easier than ever!

 

enhancedBrowser.ProxyServer = Properties.Settings.Default.ProxyServer;

 

Project settings are managed through the project’s properties > Settings tab.  For more information on the Settings capabilities within .NET, read this article on MSDN.  Unfortunately, the article still targets .NET 2.0; however, I haven’t seen a difference with VS2008 and .NET 3.5.

 

To couple with the ability to manage our proxy setting in user settings, I built up a quick Options form—a text box, button, and a label that saves the user input back into the user settings.  That form is also included in the project, but not required—as I mentioned, you could simply hardcode the setting in, it just depends on usage.

 

What I’ve Learned…

 

Without going into too much boring detail, I’d like to point out that my last “real” forms-based development was VB6–-and that was for prototyping in a theory class for my associate’s degree.  Before that, I did some forms work in VB3.  Yeah, 3.0.  Remember Windows 3.11?  Good times.

 

Since then, I’ve been a web guy.  I love the “reach” of web applications and, with things like AJAX and Flash, the UI capabilities of the web are AMAZING.  The proof is that this entire venture (of encapsulating Pandora in a window of it’s own) speaks volumes to that—years ago, we were trying to run desktop applications in our web browser!

 

But, this project has been fun and no learning ever goes to waste.  I have a better appreciation for some of the “freebies” that we get in the web (we design forms, but the fact that they exist and their show/hide state is the browser’s responsibility), but liked having the design-time control for placement and that, inspite of resolutions and fonts, I copied the app to my XP laptop and it worked like a champ.

 

All in all, a cool venture and learning experience in the Windows Forms arena—giving me another option to look at (more seriously) when designing applications that may not NEED to be web tools. :)

kick it on DotNetKicks.com





Flash and Proxy Support on .NET WebBrowser Controls

3 01 2008

At work, I’ve been dealing with Big Brother for the past few weeks (well, before the holiday break)—attempting to both accomplish a bit of work and some play in light of our annoying filter (blocking MSFT blogs, forums, community sites, and almost all useful search engines).

I love Daniel Mackey’s Pandora’s Box application, an encapsulation of the web browser for playing Pandora; however, it doesn’t support proxy servers.  I found a few other players, but, it appears, that IE 7 screws up a few things and the proxy settings don’t work correctly.  Bleh.  So, okay, it’s web browser and I’m a web developer—this can’t be that hard.

Heh.  If I only had a dollar for each time I said that…

Creating a Flash-enabled WebBrowser Control

One of the drawbacks to the current .NET WebBrowser control is that Flash, for some reason, can’t operate.  It just sits there—staring back at you.  I came across a post a few months ago to fix this.  It was originally targeted at 2.0, but seems to work just fine in 3.5

The fix?  Create a new user control and inherit from the WebBrowser control.  The only work is to override the WndProc method:

protected override void WndProc(ref Message m)

{

switch (m.Msg)

       {

             case 0×021:

             case 0×201:

             case 0×204:

             case 0×207:

                     base.DefWndProc(ref m);

                    return;

}

base.WndProc(ref m);

}

If you’re not familiar with how Windows forms messages are processed, you can find more information on MSDN.

Important: If you’re developing on an x64 (64–bit) machine, you must change your compile target platform to x86 (32–bit).  The WebBrowser control renders according to your platform—x64 in 64–bit, x86 in 32–bit.  Most of us use the 32–bit version of Internet Explorer on our x64 Windows because plugins, such as Flash, only have 32–bit editions.  In this case, Flash will not be able to load under the x64 WebBrowser control and will throw errors.

Implementing the Flash-enabled WebBrowser Control

I’m not real original on my control names… my derived control is called FlashWebBrowser.  Good deal.

To implement the control, add a Form to your page and size accordingly.  You can drag/drop your controls onto the form; however, for this example, I chose to do everything in code behind.

public partial class PandoraForm : Form

{

private FlashWebBrowser flashBrowser = new FlashWebBrowser();

 

       public PandoraForm()

       {

            InitializeComponent();

            flashBrowser.Dock = DockStyle.Fill;

            flashBrowser.AllowWebBrowserDrop = false;

            flashBrowser.IsWebBrowserContextMenuEnabled = false;

            flashBrowser.WebBrowserShortcutsEnabled = false;

            flashBrowser.ScriptErrorsSuppressed = true;

                       

            Controls.Add(flashBrowser);

            Load += new EventHandler(Form1_Load);

       }

Our flashBrowser object applies a few common attributes, such as filling the form and locking out the context menus.  Also, you’ll notice ScriptErrorsSuppressed.  Any JavaScript errors will pop-up automatically using the WebBrowser control (on IE, they’re visible in the status bar and only displayed if you explicitly have the option set to); this causes quite a bit of annoyance using services like Pandora, Google, and Flickr.  ScriptErrorsSuppressed will… suppress those errors.

Information: I’d like to caveat that last statement with a note.  It will USUALLY suppress those errors.  For some reason, IE 7.0 seems to ignore that statement and still throws the errors.  *sigh*  More information can be found ala Google.  I’m still researching this and hope to have a better understanding soon.

Our final method, Form1_Load as specified above, simply contains our flashBrowser’s Navigate method.

private void Form1_Load(object sender, EventArgs e)

{

flashBrowser.Navigate(“http://www.pandora.com/?cmd=mini”);

}

Implementing Proxy Support for the WebBrowser Control

I haven’t cleaned this up into the FlashWebBrowser control yet, but I wanted to post this up for those interested.  Proxy support is REALLY useful if you’d like a particular application or service to use a proxy server, but don’t want to deal with the hassle of constantly changing your Internet settings.

You could use the HttpWebRequest object, pass along a WebProxy, and go that route.  However, quite honestly, I haven’t worked out how you can apply that to a WebBrowser control—only at the console.  I’m sure it can be done and may be more secure than this method, but this forum code works.

Cleaned up, the code looks like:

public struct INTERNET_PROXY_INFO

{

public int dwAccessType;

public IntPtr proxy;

public IntPtr proxyBypass;

};

 

[DllImport("wininet.dll", SetLastError = true)]

private static extern bool InternetSetOption(IntPtr hInternet,

int dwOption, IntPtr lpBuffer, int lpdwBufferLength);

 

private void RefreshIESettings(string strProxy)

{

const int INTERNET_OPTION_PROXY = 38;

const int INTERNET_OPEN_TYPE_PROXY = 3;

 

INTERNET_PROXY_INFO struct_IPI;

 

// Filling in structure

struct_IPI.dwAccessType =

INTERNET_OPEN_TYPE_PROXY;

struct_IPI.proxy =

Marshal.StringToHGlobalAnsi(strProxy);

       struct_IPI.proxyBypass =

Marshal.StringToHGlobalAnsi(“local”);

 

       // Allocating memory

       IntPtr intptrStruct =

Marshal.AllocCoTaskMem(Marshal.SizeOf(struct_IPI));

 

       // Converting structure to IntPtr

       Marshal.StructureToPtr(struct_IPI, intptrStruct, true);

 

       bool iReturn = InternetSetOption(IntPtr.Zero,

INTERNET_OPTION_PROXY,

intptrStruct,

Marshal.SizeOf(struct_IPI));

}

wininet.dll is the Windows library that contains most of the internet functions used by Windows and Windows-based applications.  Proxy settings are not the only things configurable using this API; for more information, read here.  Also, for a full understanding of what this code is doing, MSDN has a nice walkthrough demonstrating the various options and how to get/set them.

With that method added to our project, there’s only one change needed—we need to call our RefreshIESettings method prior to the Navigate method of our WebBrowser control.  Our Form1_Load method now looks like:

private void Form1_Load(object sender, EventArgs e)

{

RefreshIESettings(“myproxy.server.com:99″);

       flashBrowser.Navigate(“http://www.pandora.com/?cmd=mini”);

}

I want to integrate the proxy settings INTO the WebBrowser control—and still might.  When that’s done, I’ll post up the code.  For now, however, that’s it.  We now have a WebBrowser control and a baby Windows Forms application that loads up a Flash site, like Pandora AND goes through a proxy server (so I can sit and listen to tunes at work OR be productive and access the MSFT community forums).  Good deal.