Archive

Posts Tagged ‘.NET’

Central Error Tracking for Deployed Systems

January 11th, 2010 Matt J. Wilson No comments

At one of my previous employers, we had several remote deployments (hundreds, actually) and a need to track remote errors in a central location; we utilized an ASP site to visually display this combined collection of errors.

I’ve taken the time to rewrite my own central error tracking mechanism from scratch. This module includes text logs that automatically rotate themselves once a file reaches a certain size (no more trying to have someone email you a 3 GB text file), useful information about what type of error occurred, and a SQL CE database that stores these errors in a local database, counting the number of incidences and whether there is fresh information to report on a schedule to the central database.

There is also a central web service that accepts these exception reporting requests and inserts them into a central SQL database for you to do with what you will (ASP website, Excel sheets with queries, etc., etc.). You can find a copy of this solution (Visual Studio 2005 written in C#) here.

Categories: Programming Tags: , ,

Packaging a .NET Deployment Project into a Single EXE

February 13th, 2009 Matt J. Wilson No comments

So you want to package your MSI and EXE into a single EXE for distribution?  There’s no way to do it using .NET, but Inno Setup is an excellent, free utility that will allow us to create a bootstrap utility.  You will also need to download the ISTool pack to utilize the isxdl.dll.

This tool will ensure the user has the proper .NET framework installed; if not, it will retrieve it from the Microsoft site and begin installing it for them.   It will also retrieve your EXE and MSI files from any web location you specify, allowing them to automatically download and install (or uninstall later) for the user.

Enough rambling, here’s the code to use and enjoy (please note my link to the .NET Framework and registry checking are for 2.0):

[_ISTool]
EnableISX=true

[Setup]
AppName=YourAppName
AppVerName=Your App Version 1.0.0
MinVersion=4.1,4.0
DefaultDirName={pf}\Your Default Directory
DefaultGroupName=Your Default Group Name
Compression=lzma
SolidCompression=true
OutputBaseFilename=Your Output File Name
DisableDirPage=true
DisableProgramGroupPage=true
DisableReadyPage=false
DisableReadyMemo=true

[Files]
Source: C:\Program Files\ISTool\isxdl.dll; Flags: dontcopy

[Messages]
WinVersionTooLowError=YourAppName requires Windows 2000, Windows XP or later.

[Icons]
Name: {group}\Uninstall YourAppName; Filename: {uninstallexe}

[Code]
var
dotnetRedistPath: string;
downloadNeeded: boolean;
dotNetNeeded: boolean;
memoDependenciesNeeded: string;
uninstaller: String;
ErrorCode: Integer;

procedure isxdl_AddFile(URL, Filename: PChar);
external 'isxdl_AddFile@files:isxdl.dll stdcall';
function isxdl_DownloadFiles(hWnd: Integer): Integer;
external 'isxdl_DownloadFiles@files:isxdl.dll stdcall';
function isxdl_SetOption(Option, Value: PChar): Integer;
external 'isxdl_SetOption@files:isxdl.dll stdcall';

const
dotnetRedistURL = 'http://download.microsoft.com/download/5/6/7/567758a3-759e-473e-bf8f-52154438565a/dotnetfx.exe';
const
exeURL = 'http://www.pathtoyoursite.com/setup.exe';
const
msiURL = 'http://www.pathtoyoursite.com/Installation.msi';

function InitializeSetup(): Boolean;

begin
Result := true;
dotNetNeeded := false;

if not FileExists(ExpandConstant('{tmp}\setup.exe')) or not FileExists(ExpandConstant('{tmp}\Installation.msi'))  then
begin
isxdl_AddFile(exeURL, ExpandConstant('{tmp}\setup.exe'));
isxdl_AddFile(msiURL, ExpandConstant('{tmp}\Installation.msi'));
downloadNeeded := true;
end

// See if the .NET Framework is already installed
if (not RegKeyExists(HKLM, 'Software\Microsoft\.NETFramework\policy\v2.0')) then begin
dotNetNeeded := true;
if (not IsAdminLoggedOn()) then begin
MsgBox('YourAppName needs the Microsoft .NET Framework to be installed by an Administrator', mbInformation, MB_OK);
Result := false;
end else begin
memoDependenciesNeeded := memoDependenciesNeeded + '      .NET Framework' ;
dotnetRedistPath := ExpandConstant('{src}\dotnetfx.exe');
if not FileExists(dotnetRedistPath) then begin
dotnetRedistPath := ExpandConstant('{tmp}\dotnetfx.exe');
if not FileExists(dotnetRedistPath) then begin
isxdl_AddFile(dotnetRedistURL, dotnetRedistPath);
downloadNeeded := true;
end;
end;
SetIniString('install', 'dotnetRedist', dotnetRedistPath, ExpandConstant('{tmp}\dep.ini'));
end;
end;

end;

function NextButtonClick(CurPage: Integer): Boolean;
var
hWnd: Integer;
ResultCode: Integer;

begin
Result := true;

if CurPage = wpReady then begin

hWnd := StrToInt(ExpandConstant('{wizardhwnd}'));

// don't try to init isxdl if it's not needed because it will error on < ie 3
if downloadNeeded then begin

isxdl_SetOption('label', 'Downloading YourAppName Components');
isxdl_SetOption('description', 'YourAppName needs to install some components. Please wait while Setup is downloading extra files to your computer.');
if isxdl_DownloadFiles(hWnd) = 0 then Result := false;
end;
if (Result = true) and (dotNetNeeded = true) then begin
if Exec(ExpandConstant(dotnetRedistPath), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then begin
// handle success if necessary; ResultCode contains the exit code
if not (ResultCode = 0) then begin
Result := false;
end;
end else begin
// handle failure if necessary; ResultCode contains the error code
Result := false;
end;
end;
FileCopy(ExpandConstant('{tmp}\Installation.msi'),  ExpandConstant('{app}\Installation.msi'), false);
FileCopy(ExpandConstant('{tmp}\setup.exe'),  ExpandConstant('{app}\setup.exe'), false);
end;
end;

function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
var
s: string;

begin
if memoDependenciesNeeded <> '' then s := s + 'Dependencies to install:' + NewLine + memoDependenciesNeeded + NewLine;
s := s + MemoDirInfo + NewLine + NewLine;

Result := s
end;

[Run]
Filename: msiexec.exe; Parameters: "/i ""{tmp}\Installation.msi "" /qb"

[UninstallRun]
Filename: msiexec.exe; Parameters: "/x ""{app}\Installation.msi "" /quiet"

Thanks to the various posts on the web that gave me the basic understanding of Inno Setup and allowed me to create this script.

Categories: Programming Tags: ,

Posting a File using the WebBrowser Class

February 12th, 2009 Matt J. Wilson 1 comment

So you have a WebBrowser object in .NET that you would like to use to automatically post a file to a given location?  You can probably figure out how to set values on this page:

<input type="text" name="myTextField">
// Update myTextField with a value
webBrowser.Document.All["myTextField"].SetAttribute("value", "I set your value");

But how do you update this?

<input type="file" name="myFileField">

You can’t simply use the SetAttribute function, as there is no attribute to correctly set; this was done intentionally to prevent users from using shady Javascript to automatically capture and send files from a page.  So how do you do it?  Something even more shady:

HtmlElement element = webBrowser.Document.GetElementById("myFileField");
element.Focus();
System.Threading.Thread.Sleep(1000);

// Perform SendKeys to fake the browser into setting the file name
SendKeys.SendWait(@"C:\Path To My File\test.txt");
SendKeys.Flush();

I hope that Google picks this up and saves someone else the thirty minutes worth of their life that I wasted attempting to figure out a solution.

Categories: Programming Tags: , ,