Click-Once Deployed WinForms Receiving QueryString

Share

Have you ever tried to pass parameters on the query string to one of your "click once" web deployed WinForms application? If you have, you’ll likely end up with an empty query string, even after following the directions on the following MSDN pages:

http://msdn2.microsoft.com/en-us/library/system.deployment.application.applicationdeployment.activationuri(VS.80).aspx
http://msdn2.microsoft.com/en-us/library/system.deployment.application.applicationdeployment.activationuri.aspx
http://msdn2.microsoft.com/en-us/library/ms172242(VS.80).aspx

I spent countless hours debugging and researching this issue, finding no answers anywhere and finding several people posting questions in forums about this issue… all with no resolution!

Here are the general directions from MSDN:

1. Mark your WinForms application as being able to receive query string parameters (right-click project/properties/publish/options, check "Allow URL parameters to be passed to application").
2. In your code, you access the query string as so:
(new Uri(AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData[x])).Query

I tried a million times trying to get my parameters to pass through to my application. Here’s how I was testing it:

1. Deploy your WinForms application (right-click project/publish, fill in path info, click next, etc… until published).
2. Browser opens up to something like: http://localhost/myapp/publish.htm
3. Click on address and add "?test=whatever" so the full URL looks like: http://localhost/myapp/publish.htm?test=whatever and hit enter to reload publish.htm with those paramters.
4. Click the "run" button on the publish page.
5. App opens up, but the query string is blank: (new Uri(AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData[x])).Query

As it turns out, my code was right all along. The trick is in the URL. Forget the publish.htm page. It can’t do it. What you need for the URL is this:

http://localhost/myapp/myapp.application?test=whatever.

That’s the trick to it. This bypasses the publish page altogether and launches the application immediately AND your query string WILL have the proper data in it!.

Share

Windows Vista Backup – Can’t Backup!

Share

Most of my tech blogs are written to provide a solution. This time, I’m just going to rant…

First, a nice feature of Vista is that it monitors the drive status of your hard drives and reports to you when impending doom approaches and gives you the opportunity to back up the failing drive immediately:

So, the obvious step to take is to take Vista up on its offer and back up your dying drive. So, I did. Rediculously, Vista absolutely insists that I also back up my C drive to the same backup location at the same time!!! Well, guess what Microsoft, I DON’T NEED TO BACKUP MY 500GB C DRIVE!! I only need to backup my dying 80GB drive. At the moment, I don’t have space to backup C. Check out this screen shot. It actually says:


“The disk that Windows is installed on will always be included in the backup.”


Notice that the C-Drive’s check box is grayed out? You CAN’T UN-select it!

I’m finding a lot of things that I don’t like about Vista. Most of the nasty things have to do with its paranoid tactics against piracy that has more of an effect on ligitimate users than on pirates as well as rediculous blockades against your OWN hardware and your OWN purchased “premium content” with “content protection”. It’ll actually intentionally degrade your audio if you’re playing music THAT YOU PAID FOR, but your hardware doesn’t have all of the expensive, top of the line, encryption built into the hardware. It will do the same for video. In some cases, it will just shut off your audio or video if you have any audio or video hardware in your computer that’s not 100% hardware secured… and EVERYONE does.

Ugh!

Please visit my online store: www.MichaelsAttic.com.

Share

Windows Vista – Can’t add users to shared folder

Share

There’s a bug in Windows Vista (who’d o’ thunk?). If you enable file sharing, then attempt to add a user to the share using this window:


you may get the error “Uable to locate user”. This is caused by the user name and login name being different. You’ll need to make them both the same to add the user. After you add them, you can change the user name and login names to be different.

Please visit my online store: www.MichaelsAttic.com.

Share

Generate Scripts for each object to seperate files in SQL Server 2005

Share

Update (2007-04-27): [As of the final release of SQL Server 2005 SP2, this problem no longer exists! You can generate scripts for each object into seperate files]

Remember in SQL Server 2000 Enterprise Manager where you could generate scripts for all objects in the database to a seperate script file for each object? Now in SQL Server 2005, in SQL Server Management Studio, the ONLY option is to generate all objects to ONE file. This makes it impossible to use external tools like WinMerge to compare two folders of files to find which objects are different.

There is a solution!
Microsoft realized the error of their ways and fixed it. You need to download SQL Server 2005 SP2 CTP (Community Technology Preview… in other words "beta"). DON’T INSTALL THIS ON A PRDUCTION MACHINE! I suggest installing it in a virtual machine or possibly a development machine, but certainly NOT a production machine! YOU HAVE BEEN WARNED!

After you get that installed (and it’s a hefty install… I think it’s about 292MB), when you launch the new SQL Server Management Studio, you’ll have the ability to generate script to multiple script files:

  1. Start SQL Server Management Studio.
  2. Connect to your database server.
  3. Right-click your database.
  4. Choose "all tasks".
  5. Choose "Generate Script".
  6. Now, you’ll have options on the dialog box to generate a seperate file for each object. By default it will generate all to one file.

Please visit my online store: www.MichaelsAttic.com.

Share

Keeping Background Images in MasterPages

Share
DotNet, .NET, C#, MasterPages, background-image
 
Have you ever put a background image in an element on a MasterPage, only to find that the image won’t display if you have content pages in another folder?  Here’s a quick and dirty solution:
  1. On your element that contains the background-image, give it a name attribute (name="MyOjbject").
  2. On the same element, add another attribute:  (runat="server").
  3. Now, in your code-behind file, on the Page_Load(…) event handler, add the following code:

MyObject.Style["background-image"] = "url(" + ResolveClientUrl(MyObject.Style["background-image"].Split(‘(‘)[1].Split(‘)’)[0]) + ")";

That’s it!  Now you get the following advantages over other hacks:

  1. The only place you maintain the image is in the same place you always have… in the background-image in the style.
  2. The image remains visible at run-time in all content pages, regardless of where they’re located (how deep they are in other folders).
  3. The image remains visible in VisualStudio at design time.

 You’re done!

That big line of code is kind of complicated and really, for readability, could be broken down into the following:

string[] Image1 = MyObject.Style["background-image"].Split('(');
string Image2 = Image1[1];
string image3 = Image2.Split(')');
string imageurl = Image2[0];
string fixedimageurl = ResolveClientUrl(ImageUrl);

What’s really going on?

Well, the original problem is that if you have a background image hard coded into an element on your master page, content pages that derive from that master page, who are located in a different folder, will have the SAME image path, which is not valid from within the other folder. The code above figures out what path the content page is in and fixes the URL path of the background image attribute.

The image path is in the style element, within the "background-image" section as something like: "url(MyImages/MyPicture.jpg)". The code above parses that string by stripping off everything before the "(", including the "(". Then it strips off the ")" and anything after it. What’s left is the raw URL of the image. It then passes that to the method "ResolveClientUrl". This method figures out where you are and how to build a path that goes back to that URL. Then we wrap it in url(…).

That’s it.

Share

Naming Conventions

Share

I’ll get to “Naming Conventions” after a short story, so please humor with your time for a short moment… It’s relevant, I promise!

People tend to get really emotional when choosing a naming convention that they’re going to apply to the software they write. That’s too bad, because that closes their mind to improvement. When I started programming in 1982, naming conventions were neither a concern of mine nor a possibility because of the limitations in the languages I was using (AppleSoft BASIC and 6502 Machine Language). AppleSoft BASIC only allowed a whopping TWO unique characters for variable names. Subroutine names were non-existent because code was identified not by labels, but by line numbers. In Machine Language, routines were identified by the memory address the instructions resided and variables were also memory address (in HEX).

As time moved onward and technology improved, I got involved in Pascal around 1984. It was Apple Pascal and I never did much with it. I pretty much stuck to what I knew which was still AppleSoft BASIC and Machine and Assembly Language. In 1988 I started college and was reintroduced to Pascal. I never adopted a naming convention on that platform (MVS Pascal) because my assignments were so short, my programs had at most, 5 procedures.  And, the concept of a naming convention was still foreign to me at the time.

But, I got a part time job at a local company doing computer graphics and first heard about a language called "C". It sounded intriguing so I bought Microsoft Quick C. It came on 5.25" floppy disks and I ran it on a 2 floppy drive Z80 PC clone card plugged into my Apple ][GS. I got pretty heavy into C and achieved "Hacker" status (this was back when "Hacker" was a good thing… it meant it was someone who spent all their waking time trying to learn everything about a particular piece of technology regardless of whether they used their knowledge for good or evil). I was a "good" hacker. Bad hackers were called "crackers" in those days.

Anyway, as I upgraded my computer to a 386sx 25MHz machine with an actual hard drive in it and Super VGA graphics, I wanted an Apple ][GS emulator, so I decided to try to write one (yes, I know… a huge undertaking that was doomed to never finish). I had all 3 volumes of the Apple ][GS Toolbox manuals (hard cover, in those days). I never got very far with that project. Instead, it turned into a different project… a GUI library for DOS programs. I have to say, to this day, it’s probably my proudest piece of work. It provided full GUI capability for DOS programs.

So, what about naming conventions???

OK, OK! The point of all that was to lead you into where why and how I came about a conscious choice to implement an actual naming convention in my code. As I was discussing the DOS GUI library… Apple had already implemented a naming convention for their toolbox libraries. It basically went like this:

  1. PascalCase (everything is lowercase, unless it’s made of multiple words, in which case, the 1st letter of each word is uppercased).
  2. No underscores.

Uh, OK. I think that was pretty much it. I liked the way the code was easy to read (no cryptic, half-hazardly, made up abbreviations or prefixes. Since my DOS GUI library used many of the same data structures that were in the Apple manuals, I had already, by default, started using that convention.

Function names were basically made up of a verb plus a noun. For example:

  • ShowWindow()
  • HideWindow()
  • SetText()

and so on… The naming convention was good, but it was not perfect. For example, the type name I used for say a window structure was called "Window" and some of my variables of type "Window" were also called "Window". This made parts of the code somewhat confusing, because when you saw "Window", was the code referring to a type or an object? Later, I upgraded to C++ (around late ’89 or so) and basically continued the same naming convention.

Along came Borland with Delphi. Well, actually, Turbo Pascal had been around for quite a while. Around 1993 or ’94, I got neck deep in Delphi. Borland used basically the same naming convention, but they had extended it. I didn’t realize it at first, but they prefixed all of their types with "T" (meaning "Type", not "Turbo" as I had thought for years looking at Turbo Pascal code). I thought that was a pretty cool idea. That separated the type name from the variable name. So, my code that declared a variable named "Window" of type "Window" went from looking like this:

Window Window;

to this:

TWindow Window;


Now, it was pretty clear. TWindow was the type and Window was the object. This added another similar benefit: By sticking with a convention on type names, I guaranteed to completely avoid the problem of having to think up some less than prime name for a variable. For example, with the old convention, to avoid naming a window variable with the same name as the Window type, I’d have to do something dorky like this:

Window TheWindow;

I hated that. I looked really unprofessional and was unnecessary. Now, when I have a variable that represents a window, I can actually call it "window" and have NO naming conflicts! I stuck with that convention for nearly 10 years.

2001: Along comes .NET
With the introduction of .NET, came the introduction of Microsoft’s new naming convention; the .NET naming convention. It was, not surprisingly, nearly identical to the naming convention I’d been using, with the following modifications:

  1. No prefixes.
  2. No abbreviations
  3. Acronyms more than 2 characters long are lower case except for the 1st letter.
  4. camelCase instead of PascalCase.
  5. No underscores "_".

The rest of the naming convention was pretty much the same. This is "no prefixes" rule meant not prefixing my types with "T". It also FAILED to address a way to distinguish between type names and variable/object names. Because of that, I continued to keep the "T" prefix for a year or so. Later, I decided to follow the "No Prefixes" rule by changing it to a suffix and to follow the "no abbreviations" rule, so that meant spelling it out "Type".

So, now a type that represents a window is now called, "WindowType". I decided to enforce this on myself for ALL types (not just classes), but for structs, classes, enumerations, etc… For the most part, this has worked out well.

As I wrote more and more software, I started noticing shortcomings of both mine and Microsoft’s naming convention. For example, what do I name a MenuItem object? Suppose that I’ve got a menu bar with a "User" menu and a "Group" menu. Let’s suppose that both of them have the following menu items under them:

  1. New
  2. Find
  3. Edit
  4. Delete

Well, you can’t have 2 menu items called "NewMenuItem" (one for the User menu and one for the Group menu)… The compiler just won’t allow it. So, there needs to be a way to specify that one belongs to the User’s menu and the other to the Group’s menu. Easy, just call the one under the User menu, UserNewMenuItem and the one under the Group menu, GroupNewMenuItem. Seems like problem solved, right? Wrong. Supposed the program allows you to select multiple items and edit them together… as a group. See where I headed yet? If I had a menu for that, I might want to label it "Group Edit". So, the menu item would be called "GroupEditMenuItem". So, what do I call the Edit menu item under the Group menu? According to the rule, it’d be "GroupEditMenuItem". Believe it or not, I’ve run into this type of situation in the real world countless times! So, I extended the naming convention to account for this problem. Violate the "No underscores" rule and put an underscore between the menu name and the menu item name. So, the Edit menu item under the Group menu would be called, Group_EditMenuItem. The menu item labeled "Group Edit" that allows the user to edit multiple items together, as a group, would be called "GroupEditMenuItem". Problem solved. Yah, really this time it is.

This new convention solves similar name conflicts in dialog boxes with tabs or group controls. For example, you may have a dialog box with multiple tabs. Each tab may have an "Edit" button. You certainly can’t call each one EditButton. Instead, you prefix each edit button with the text from the tab in which it resides. So, if you had a dialog box with three the three tabs, "User", "Group", "Security", and each of those tabs had buttons with "Edit" on the label, the first one would be "UserTab_EditButton", then "GroupTab_EditButton", and finally, "SecurityTab_EditButton".

Just call it what it is. Call a button a button.
Notice VB scripters, that I do not name my buttons "cmdEdit" etc…? There are multiple reasons for this:

  1. Buttons are "Buttons", they’re NOT "Commands" nor "Command Buttons". That terminology is unique to ONLY Visual BASIC. No other language or technology has that naming oddity.
  2. "cmd" is an abbreviation and is confusing to non VB programmers.
  3. "What it is" belongs at the end of the name, not the beginning. When you’re speaking, you don’t say, "Click the button EDIT". You say, "Click the Edit button". So, if you name your edit button as "EditButton", it reads like you speak. It’s much clearer and looks much better.
  4. DotNet actually has objects of type "Command" that have nothing in the world to do with buttons, so "cmd" looks like it’s talking about a command object, NOT a button object.

Avoiding Abvs
I’ll bet you at least 30% of the readers had a hard time deciphering "Abvs". Question: Why should I write anything that I know will be confusing to a large percentage of the readers? The answer is, "I should not!". This means, NO ABBREVIATIONS! Just spell it out. The extra keystrokes will not give you a heart attack from the extra exorcise. Believe it or not, for the past 15 years, at least, source code editors have had search as you type features built in. I rarely type the full name of any of my types, variables, or methods. So, I’m not saving keystrokes by crunching my label names down so low. And, in this day of hundreds of gigabyte hard drives, I’m not really saving space either. Hard drives are so big that I couldn’t even dream of filling one up with my own keystrokes.

By avoiding abbreviations:

  1. My code is legible by 100% of all readers.
  2. Readers of my code don’t have to make out a cheat sheet with all of my funky abbreviations.
  3. Joe Blow’s abbreviation rules might conflict with mine, so why have them?
  4. My abbreviations will be confusing to you. Your abbreviations will be confusing to me.
  5. What’s the universal rule for abbreviating a brand new type? Answer: There isn’t one.

So, every one’s better off when you avoid abbreviations.

Well, I’ve babbled on long enough. I’ll conclude with the formal list of rules for a good naming convention that can work in almost any programming language without modification:

  • By default, everything is lowercase.
  • If a label is made of multiple words, capitalize the 1st letter of each word (PascalCase).
  • Put "Type" at the end of all types (except enumerations).
  • Enumerations: End with "Enum" or "Types" (with an "s"). Name your instances "TypeOf…" For example:

  1: private enum DataBaseTypes
  2: {
  3:    Microsoft,
  4:    Oracle,
  5:    MySql,
  6:    FireBird
  7: }
  8: 
  9: private DataBaseTypes TypeOfDatabase;
 10: 

  • Objects are given a descriptive name + object type. For example, type WindowType, instance window.
  • Visual components are given the same name as the displayed text on them, when feasible. For example, a button with "OK" on it would be called, "OKButton". A check box with the text "Enabled" would be "EnabledCheckBox", etc…
  • Components in a hierarchy (like menu items in a menu structure, objects in a multi-tab control) have the name of the parent objects prefixed in front of them and each parent is separated from its child in the name with an underscore.

Conclusion:

When you’re writing code, you’re producing two products:

  1. The compiled software product.
  2. The source code.

It’s our responsibility, as programmers, to make the users’ jobs as easy as possible. It’s our responsibility to each other to make each other’s jobs as easy as possible. This means avoiding the ancient practice of saving bytes or keystrokes by making cryptic source code and instead making our source code read as much like English as we can. This makes our source code self-documenting in most cases and a pleasure to maintain.

The Microsoft .NET Naming Convention Guidelines can be seen here:

http://msdn.microsoft.com/en-us/library/ms229002.aspx

Share

Pass BLOBs to Oracle Stored Procedures

Share

Probably the most difficult task that I’ve had to conquer in quite a while is something that’s so mundane and so simple in other database products… that being the the ability to pass a large binary object (a.k.a. “BLOB”) to a stored procedure in Oracle.

My God! Were these people smoking crack when they designed this “feature”?? They would have to try really hard to make it more difficult than they did. At first try, it seemed to have worked, I mean, I successfully sent binary streams of files to my first Oracle stored procedure that accepts BLOBS. Then, later, it all fell apart with odd errors. As it turns out, you can pass up to 32KB directly into a stored procedure BLOB parameter with no problems. It’s when you pass a BLOB that’s BIGGER than 32KB to an Oracle stored procedure where all the “fun” begins!

But first, let’s take a look at a simple Microsoft SQL Server stored procedure that accepts BLOBs (and works incredibly well with BLOBs as large as 2GB):

create procedure MicrosoftBlobProcedure(@MyBlob image) as begin

    insert into MyBlobTable (MyBlobField) values (@MyBlob);

 

end

Pretty straight forward right? Well yes… for Microsoft SQL Server that is. Now, let’s look at the equivelent for Oracle:

 

create or replace procedure OracleBlobProcedure(p_MyBlob blob)
as begin
insert into MyBlobTable (MyBlobField) values (p_MyBlob);
end;

OK, the above Oracle procedure works just fine as long as you’re passing in 32KB or less!!! If you try passing in anything greater than 32KB, you’ll start getting useless error messages.

So, how do you fix it? You must change BOTH your procedure and radically change the code that calls it. First, the rewrite of the stored procedure:

 

 

create or replace OracleBlobProcedure(p_MyBlob out blob)
as
l_MyBlob blob;
begin
insert into MyBlobTable (MyBlobField) values (Empty_Blob());
l_MyBlob := p_MyBlob;
return l_MyBlob;
end;

So, what’s up with that you say? Here’s what: Notice that the parameter is now defined as an OUT variable?!?!? Instead of passing your data IN to the procedure, the procedure will pass the variable OUT to you! Just hang on! It gets worse!

Like I said, you don’t pass data INTO the procedure, instead it passes a reference back out to your calling code. Instead of the procedure inserting your BLOB data directly into the table, the procedure instead inserts the results of a call to the function Empty_Blob(). This basically creates a reference to an empty BLOB object. Then assigns it to your local blob variable, then returns the local blob variable back to your code that called the stored procedure. It gets worse!

So, the stored procedure is now DONE and you haven’t passed your data in!!! Well, you do that AFTER the stored procedure completes. No really! Wait! Where are you going?

OK, now we have to jump over to your calling code. We’ll use C# as an example. First, you have to create a transaction (from your calling code) before you call the stored proc. Then you open your database connection, then call the stored proc (passing it NOTHING!). You’ll get back a reference to the empty BLOB created inside the stored procedure. From here, you write your bytes to the referenced object, then end your transaction, then close your connection.

Makes perfect sense, right??? NOT! But that’s the ONLY way to do it! Here’s the C# code to accomplish this:

 

 

using System.Data.OracleClient;

/*… bunch of clutter …*/

private void WriteBlobToOracleAsIfImSmokingCrack(byte[] MyBytes)
{
OracleCommand command = new OracleCommand();
command.connection = new OracleConnection();
command.connection.ConnectionString = “”;
Transaction tx = command.connection.BeginTransaction();
command.CommandType = CommandType.StoredProcedure;
command.CommandText = OracleBlobProcedure;
OracleParameter parm = new OracleParamter(“p_MyBlob”).Direction = out;
command.Parameters.Add(parm);

    command.connection.Open();
command.ExecuteNonQuery();
OracleLob MyLob = command.Parameters[“p_MyBlob”].value;
MyLob.write(MyBytes, 0, MyBytes.Length());
tx.EndTransaction();
command.connection.Close();
}

So there you have it. It was all so obvious, right! I am at a loss as to what in the world they were thinking when they came up with this!! It’s just pure insanity!

Please visit my online store: www.MichaelsAttic.com.

Share