Wednesday, August 12, 2009

MSI Package Uninstall Issue

So what happens, you write some C# code to go with your WIX installer. The C# code only runs on uninstallation. But ... during development you write some dodgy code, it causes an exception which makes the uninstallation fail.

Take a look here,

http://blogs.msdn.com/astebner/archive/2005/12/24/507294.aspx

And here,

http://www.advancedinstaller.com/user-guide/qa-forced-uninstall.html

I found that msizap didn't work for me, but what did was going to the directory '%windir%\installer' and searching for the most recent file, editing it with orca, and removing the custom action causing a problem did the trick nicely.

More on WIX

Since my last blog post I have found a lot more out about WIX which is worth noting. It is pretty easy to add a custom action like this,


The custom actions can also be written in C# by selecting 'new project' in visual studio and selecting 'C# custom action project'.

Here is a bit more info,


Here is some more about dealing with databases from WIX,


Later on I will try and give some more specific examples from the WIX package I am creating. It is pretty complicated though so it is hard to know where to start.

Tuesday, August 11, 2009

WIX Installing Database

WIX is very powerful, but can be quite fiddly to get running.

Take a look at this if you are installing a database and want to select the database server and credentials,


Also look at the WIX manual,


Once you have done the code to select the database server and credentials you can put that connection string into an XML file using code like this,

Monday, August 10, 2009

MD5 Encryption

A good link to do with MD5 encryption,


Scroll down to this too,

string hashedPass = MD5(aComplicatedSaltString + password);

Which is a comment someone made about adding in extra, not just the password, perhaps a user name too. This will make the string more complicated, and thus add a bit more security.

I saw another site once which I cannot find any more. It mentioned about creating what I believe was basically a salt and making that salt a random guid. The random guid is stored in the database in a separate field.

What was the purpose of this? That particular example was looking at a database which has a lot of similar rows. If you saw the rows in the database you would be able to see which fields were the same between rows because the hash values would match. If you add in a salt the data could be the same between rows, but their hash values would be different.

Here is similar code,


You can also use AES to hash information into product keys,

Insert Vs Update in a DB

I have come across this problem a lot with my database coding. We have some data to insert into the database. Depending on whether the data is new or existing will determine whether we do an insert or an update statement on the database.

I find that this solves the problem very nicely,

if exists(select * from Table where key = 'rowId1')
begin
update Table set datavalue = 'newValue', datavalue1 = 'newValue' where key = 'rowId1'
end
else
begin
insert into Table values ('newValue','newValue', etc, etc)
end

Simple and sweet.

ntext Database Type

The ntext database type is a unicode variable length data type in SQL server. SQL server profiler creates these fields if you save a profile to a trace table.

If we try to filter one of these trace tables like this,

select * from TraceTable where TextData like '%value%'

That is fine, but if we try to do this,

select * from TraceTable where TextData = 'value'

We get an error like this,

The data types ntext and varchar are incompatible in the equal to operator.

The solution is this,

select * from TraceTable where cast(textdata as varchar(100)) = 'value'

Thursday, August 6, 2009

Dealing with UAC

What happens if your application wants to update itself, or change files which UAC will not allow you to update without elevation. The solution is to not elevate your whole application. This would defeat the purpose of UAC in the first place.

One solution is to create a new project in VS, which might be a console app that you run invisibly for instance. The console app will do some file copying or whatever else needs UAC elevation and that is all. Right click the new UAC project you have created and add an 'application manifest file'.

Make sure this is in the manifest file,

<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>

And you will be away. So back to your unelevated program, calling this console app from your unelevated code can be done like this. What this will do when you call process.Start() is prompt for UAC elevation,

Process process = new Process();
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.Exited += new EventHandler(process_Exited);

I have left most of it out, but the important thing there is that I have said it should have no window, and the style should be hidden. I have also defined an exit event so that I can pick up when the UAC app has finished.