Visual Design and I have now officially relocated to Gothenburg. It is not my intention that this shall be a permanent condition. Meanwhile, however, the new address for Visual Design is:
Why? Because of Anette! |
![]() |
Posted by Dan Byström on September 13, 2006
Visual Design and I have now officially relocated to Gothenburg. It is not my intention that this shall be a permanent condition. Meanwhile, however, the new address for Visual Design is:
Why? Because of Anette! |
![]() |
Posted in Uncategorized | Leave a Comment »
Posted by Dan Byström on September 10, 2006
First of all, I must admit that I’m not a big fan of computer security. I don’t even run any anti virus software on any of my computers. I tried it briefly some ten years ago and my computer behaved odd all the time so I turned it off. I don’t think things are much better now. Just a couple of moths ago a friend of mine spent a day cursing and kicking his computer because an important program he had to run for his project (some sort of FTP program I think it was) refused to work. I asked him a couple of days later if he had solved the problem. You guessed it: as soon as he turned off his anti virus software he was back on track!
Of course, computer security is a terribly important field and much larger and more complicated than most of us can imagine. Nevertheless – I’ll whine over it a little anyway!
(I often get the question why I don’t get viruses when I don’t use any virus protection. The answer is very simple: when I receive a virus I don’t run it!)
Now I shall tell you a little story from a programmer’s day of life. I’ve written a piece of software that’s run by some 70 people traveling out in the fields, who several times a week need to send in large amount of data to the headquarter. Typically this data is around 3 GB or so (but can be much larger), and we can’t rely on them having access to the internet. So the solution is of course to burn the data on DVD records and send them using snail mail.
For this I have used XPBurn, which I got to work after fixing a few bugs in the source code (which I reported back to the author who released a new version but didn’t give me any credit. C’est la vie). Now a reoccurring problem for me with .NET in general and XPBurn in particular is that they both tend to lock files and refuse to let go of them.
For example, after burning files with XPBurn I have to restart my app in order to burn them again, because they’re locked. There probably is a simple solution to this, but I haven’t been able to find it. Or maybe there isn’t.
.NET is also good at locking files, for example: _bmp = (Bitmap)Bitmap.FromFile( "c:\\house.jpg" );locks the file until you dispose _bmp. The only reason I’ve been able to come up with is that .NET needs to keep multi page TIF files open, and that .NET therefore treats all images the same way. If you have a better explanation, please tell me!
In order to open an image without leaving a lock on the file you need to: using ( Bitmap bmp = (Bitmap)Bitmap.FromFile( "c:\\house.jpg" ) )
_bmp = new Bitmap( bmp );
So, when my program burned DVD records, there where sometimes peculiar errors claiming that some files was locked, although I was 100% positive that I closed them correctly. In order to get around this problem I decided that I needed to break up my burning over – don’t laugh at me now – not two, but actually three different processes (.EXE-files)! If you laugh anyway, please read on!
I split my app into three pieces:
Here’s how it goes: the main app writes an instruction file to disk specifying all files it wants to burn (and if any of them must exist on each spanned disk and the disk labels etc). Then the main app executes the Mediator and then terminates itself! The Mediator reads the instruction file and takes care of any disk spanning necessary (jobs being larger than one DVD). The user may specify how large a “full disk” is, because when using XPBurn, the job will often fail if we try to fill the disk completely. Therefore we have lowered the default “full size” to 4000Mb, which has worked fine. This limit can also be brought down below 700Mb in order to use CD records.
For each record, the Mediator then executes the actual burner, vdBurnProc, and gets notified on progress as well as completion results, offering to re-burn a failed record etc. Now where’s the point in all this? Well, the point is that when the main app terminates itself there is no chance that any files remain locked! And since vdBurnProc terminates itself after each burnt record, it can’t lock any files either. And the Mediator only touches the instruction file and nothing else! You see?
When the final record is burnt, the Mediator restarts the main app, which’s work can then continue. Although this may sound unnecessarily complicated, in practice it works like a dream!
Now I guess you wonder where all this leads up to? Can’t say that I blame you, I think I lost myself there too for awhile, but now I will get back on track!
I wanted to keep the UI for the whole burning process in the Mediator and therefore I needed a mechanism to report burning progress from vdBurnProc to the Mediator in some way. What can be easier than using plain old Windows Messages for this? Sending numeric data this way is a breeze, but then I also wanted to be able to send back a result string! Passing a string over process boundaries is not all that simple, unless we cheat! OK, let’s cheat. We use WM_SETTEXT, which for backward compatibility with 16-bit Windows actually moves the string across the process boundary for us! We will get a pointer to the string that was sent from the other process without any fuzz (or so I thought!!!). Also note that when we’re processing the WM_SETTEXT message we’re blocking the sender until we return, so let’s get out of there quickly! The code in the Mediator to listen to what vdBurnProc has to say about its place in life goes like this:
interface IBurnCallback
{
void AddProgress(int nCompletedSteps, int nTotalSteps);
void PreparingBurn(int nEstimatedSeconds);
void BlockProgress(int nCompletedSteps, int nTotalSteps);
void ClosingDisc(int nEstimatedSeconds);
uint BurnerHwnd { get; set; }
void BurnComplete(string strMessage);
IntPtr Handle { get; }
}
class InteropWindow : NativeWindow
{
private IBurnCallback cb;
private string ResultText = null;
public InteropWindow(IBurnCallback cb)
{
this.cb = cb;
CreateParams cp = new CreateParams();
cp.Parent = cb.Handle;
cp.Caption = "vdStandaloneBurn Interop Window";
this.CreateHandle(cp);
}
protected override void WndProc(ref Message m)
{
switch ( m.Msg )
{
case WM_USER:
cb.AddProgress( (int)m.WParam, (int)m.LParam );
return;
case WM_USER+1:
cb.PreparingBurn( (int)m.WParam );
return;
case WM_USER+2:
cb.BlockProgress( (int)m.WParam, (int)m.LParam );
return;
case WM_USER+3:
cb.ClosingDisc( (int)m.WParam );
return;
case WM_USER+4:
cb.BurnerHwnd = (uint)m.WParam;
return;
case WM_USER+5:
cb.BurnComplete( ResultText );
ResultText = null;
return;
case WM_SETTEXT:
unsafe
{
ResultText = new string( (char*)m.LParam.ToPointer() );
}
// inform the main thread that the result has come
PostMessage( (uint)this.Handle, WM_USER+5, 0, 0 );
// and don't block this thread anymore
return;
}
base.WndProc(ref m);
}
}
And HERE is finally what this blog post is all about! The unsafe keyword! In order to compile this code I need to compile using the /unsafe switch. I did that and I saw it was good. My DVD burning problems were finally gone in one stroke. As I said, this really works like a dream.
End of part one of the story. A year passes. Now I realize that I want to use the same solution in another project. In this case however, I really can be sure that the main app won’t lock any of the files, so I skip the Mediator. I take my vdBurnProc.exe and XPBurn.dll and throw them into the same directory as the new main application and throw in the code above into the app. Then I get a compiler error saying that I must compile using the /unsafe switch. Obediently I comply. I test the app and it works nicely!
Now this app is actually run by different users in two different ways. Some run it through Remote Desktop (Terminal Server). Those users will of course not use the burning function since it will burn records on the Terminal Server machine. When we upgrade the software it is very simple to give those users a new version. We just copy the new version into a new directory and change the desktop icon. The next time the users start the app, they get the new version.
Other users, however, run the application locally, having the binaries on their local hard drives. In order to upgrade the app for them, the following scheme is used:
Version verThis = Assembly.GetExecutingAssembly().GetName().Version;
Version verThat = Assembly.LoadFile(strOtherVer).GetName().Version;
int[] anThis = new int[] { verThis.Major, verThis.Minor, verThis.Build, verThis.Revision, 1 };
int[] anThat = new int[] { verThat.Major, verThat.Minor, verThat.Build, verThat.Revision, 0 };
for ( int i=0 ; i<anThis.Length ; i++ )
if ( anThis[i]>anThat[i] )
return false;
else if ( anThis[i]<anThat[i] )
break;
if ( Global.askMsgBox( null, false, "There exists a new version of this application. Would you like to install it?" ) == DialogResult.Yes )
{
...This is also a solution that has worked like a charm in real life. Until this Tuesday morning when the sysop woke me up and cried HELP.
What went wrong?
Because of the /unsafe switch, the “local” users got a run time error on this line: Version verThat = Assembly.LoadFile(strOtherVer).GetName().Version;
They weren’t trusted to load an unsafe assembly from a network drive. $#%&#*¤#!!!!
OK, how do we fix that? A little googling (oh, sorry, Google says this takes their trademark towards “genericide”, whatever that may mean, “A little searching using the Google search engine”, I mean) tells me that the app needs a strong name! Fine, I give it a strong name. Now the compiler tells me I must give ALL my assemblies strong names! Including the old version of NHibernate we’re using. Do I want to go further down this road? Not if I can help it. It’ll probably just get worse. What other options do I have? What is the basic problem here?
I had to use the /unsafe switch in order to execute ONE line of code (out of 200,000) which wanted to use a simple pointer!!! Is it possible to rewrite this single line in some way? All I want to do is to convert a character vector which I’m holding a pointer to into a regular .NET string. Now the Framework says that this single line of code is so dangerous that users aren’t allowed to use my app anymore! *sigh*
Every seasoned VB6 programmer out there immediately knows the answer to this one. In lack of pointers we simulate them using the API function RtlMoveMemory!!! So, visiting www.pinvoke.net we get the signature:
[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
public static extern void MoveMemory(byte[] x, uint src, int size);
Now we can easily rewrite this:
unsafe
{
ResultText = new string( (char*)m.LParam.ToPointer() );
}
Into:
ResultText = string.Empty;
byte[] buf = new byte[500];
MoveMemory( buf, (uint)m.LParam, buf.Length );
for ( int i=0; buf[i]!=0 && i<buf.Length; i+=2 )
ResultText += (char)buf[i];
And now we’re SAFE again! (Oh, should I use a StringBuilder and should I make sure that I correctly handle all Unicode characters? Feel free to fill in that gap in your mind while reading!)
So, what good is this /unsafe business when we can overcome it so easily!?!!? As long as a .NET application is allowed to “pinvoke” to the Windows API it can never be trusted!!! Its code may become a little uglier but it can still accomplish exactly the same thing as “unsafe” pointer arithmetic can do!
Do I leave any recommendations or suggestions regarding this? Or even any conclusion? No, I just wanted to tell my little real life story. Hope you enjoyed it.
Posted in Uncategorized | Leave a Comment »
Posted by Dan Byström on August 30, 2006
Apologies to my English readers: this post is about poorly written Swedish language, so it can not (or should I say, should not!) be translated.
I just received an unbelievably funny fraud letter attempt:
God dag, bäste kund!För Nordea har sommar 2006 blivit en av de mest fulla med illegala operationer. Det blir allt oftare att den konfidentiella informationen om våra kunder intresserar svindlare. Det är rätt många som vänder sig till oss för att vi skyddar deras konto mot förlust av pengar. På grund av det förklarar Nordea nästa månad för månaden av fraudkamp. Fram till 1 September skall alla våra kunder aktivera den nya kontosäkerhetssystemet. Vi har genomfört ett stort arbete för att förbättra det. Systemet har blivit kontrollerat av ledande specialister inom e-betalningssytemen och alla oberoende expeterter har redan bekräftat dess fullvärdighet vad gäller fraudbekämpning. På grund av att dessa uppgifter kan användas av kriminella, piblicerar vi inte dem i öppna källor. Du har blivit slumpmässigt vald som deltagare i systemets avslutningsprov. För tillfället föreslår vi att Du klickar på länken http://app.nordea.se/login/security.html och genom en vanlig inloggning till Internet-banking aktiverar det nya säkerhetssytemet. För tillfället kan Du märka vissa förbiseenden medan Du arbetar. Vi vet att de finns, och ber Dig därför att inte ge oss någon tillägginformation om problem som har uppståt, vi skall lösa dem på egen hand. Vi skall uppmärksamma Dig att från och med september blir Du tvungen att använda det nya säkerhetssystemet i alla fall, annars kommer Dina konton bli blockerade tills Din fulla personliga identifikation är klar. Därför föreslår vi att Du så snart som möjligt börjar tillämpa de nya säkerhetsstandarderna. Med vänliga hälsningar, |
I think this serves as a good reminder that even if you plan for a criminal career, you shouldn’t miss school so much that you don’t learn how to read and write. Maybe the gentlemen who composed the above letter should just try shop-lifting instead? 🙂
Posted in Uncategorized | Leave a Comment »
Posted by Dan Byström on May 22, 2006
A year ago I wrote "I’m working on an exciting project (in C#) where I’ve come up with a number of interesting things to write about in the future, when I have more time".
Guess what? I’m still working hard on the very same project! For 18 months I’ve been working on this with my friend and colleague Jimmy Nilsson. Jimmy writes the domain model (including data storage and also develops a deeper understanding of the customer’s business logic) while I do "the rest".
I just counted the number of source code lines in my part and found that it is made of 170,000 lines of C# code – and counting (and don’t for a second believe that you can find any duplicated code in there; I’d rather watch sports for a whole day than yield to "clipboard inheritance").
Now here is a beautiful thing: in not a single one of these 170,000 source code lines can you find a clue to that there is an SQL Server somewhere "down there". There are only nice clean objects presented to me by Jimmy’s Domain Model, freeing me to focus on creating a nice, functional user experience instead of getting dirty with how to get data off and to the database.
This is achieved by fully utilizing the concept of Domain Driven Design [Evans]. Jimmy "wraps" the database for me and presents an object model (the domain) so that I can work totally object oriented and focus on logic and UI and just forget about the persisting details. This is truly the way programming was meant to be! 🙂
Now you may just wonder who Jimmy managed to get my life so simple. He has been kind enough to tell us all exactly how in his new book Applying Doman-Driven Design and Patterns!
Posted in Uncategorized | Leave a Comment »
Posted by Dan Byström on May 18, 2006
Yesterday I had a great time at Expo-C i Karlskrona, listening to some inspiring speakers like Lennart Ohlsson and Dan North. The topics centered around languages, like Agile Languages and Domain Specific Languages. After awhile I started to realize that I really must try out Python and Ruby soon (like I’ve been told for years now).
But best of all was Eric Meyer, who was the last speaker. He almost convinced everyone that there exists a language that already delivers what the previous speakers propagated for – and more, like both strong and weak typing at the same time. This great language is… Visual Basic .NET. Afterwards Dan North said "well, it sounds just great, but… it is… VB!!!".
It will be interesting so see if Eric will manage to get rid of VB’s bad reputation. I asked him if we couldn’t have late binding in C# as well and got the obvious answer "why do you want it in C# when it’s already there in VB?". 🙂
Posted in Uncategorized | Leave a Comment »
Posted by Dan Byström on February 23, 2006
| I’ve finally begun my transformation into a totally cybernetic being. 😉
|
![]() |
Posted in Uncategorized | Leave a Comment »
Posted by Dan Byström on October 31, 2005
http://www.iunknown.com/articles/2005/10/31/do-databases-rot-the-mind
I’ve been trying to tell people for over a decade now. Here, for example.
Posted in Programming | Leave a Comment »
Posted by Dan Byström on October 26, 2005
switch ( Math.Sign(q.answer-42) )
{
case 1: q.left(); break;
case -1: q.right(); break;
case 0: Foo.Bar(); return;
}
Posted in Uncategorized | Leave a Comment »
Posted by Dan Byström on September 27, 2005
Now when we’re all anticipating Visual Studio 2005, it’s time for me to crank out a tip regarding Visual Studio 2003.
If it’s a tip concerning you depends on whether or not you’re among the unfortunate ones like me, who sometimes displeases VS in such a way that it decides to teach me a lesson – by turning most of my Forms and UserControls into regular classes so that they cannot be designed anymore!
If this hasn’t happened to you – you’re among the fortunate ones and I congratulate you. (God’s little pet, right!?)
When this disaster has struck me before I have either resumed from a backup and just moved the latest changed files back into my project, or I have tediously begun to copy the text of each damaged file to the clipboard and then deleted the file from the project, then adding a new one with the same name and finally pasting the code back into place. Not very fun at all.
Now I just discovered that there is a much easier way to recover! I just open the .csproj file in Notepad. There I’ll find XML tags like these:
<File
RelPath = "controls\vdCalendar.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "controls\vdCalendar.resx"
DependentUpon = "vdCalendar.cs"
BuildAction = "EmbeddedResource"
/>
<File
RelPath = "dialogs\FAbout.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "dialogs\FAbout.resx"
DependentUpon = "FAbout.cs"
BuildAction = "EmbeddedResource"
/>
By walking through the list of files and changing each into the desired “SubType” it is much easier to recover:
<File
RelPath = "controls\vdCalendar.cs"
SubType = "UserControl"
BuildAction = "Compile"
/>
<File
RelPath = "controls\vdCalendar.resx"
DependentUpon = "vdCalendar.cs"
BuildAction = "EmbeddedResource"
/>
<File
RelPath = "dialogs\FAbout.cs"
SubType = "Form"
BuildAction = "Compile"
/>
<File
RelPath = "dialogs\FAbout.resx"
DependentUpon = "FAbout.cs"
BuildAction = "EmbeddedResource"
/>
But then again, I may be the only person alive who can annoy Visual Studio 2003 to this extent in the first place!
Posted in Programming | Leave a Comment »
Posted by Dan Byström on July 4, 2005
| I speak of none but the computer that is to come after me, A computer whose merest operational parameters I am not worthy to calculate. And yet I will design it for you. | ||
|
— Deep Thought |
Now I know exactly how Deep Thought felt. I’m not worty to hang out with these guys, yet somehow I am. 🙂
(The rest of this blog is in swedish, if you don’t understand swedish but would like to, I recommend you take a crash course in swedish.)
Vi kommer att starta upp under sommaren för att komma igång ordentligt till i höst. Under kommande vecka kommer vi att börja med "Veckans tips", vilket antagligen kommer att bli en sanslöst heterogen läsning med tanke på allas olika bakgrund och intresse. Lita t ex på att jag inte kommer att tipsa om SQL (mitt tips i frågan är som alltid: nej 😉 samtidigt som vi har riktigt tunga SQL-experter med i gänget.
Posted in Uncategorized | Leave a Comment »