Monday, October 22, 2007

Watch your memory

Delphi has a nice feature (since version ??) to check whether you leak some memory in your project. All you have to do is set the ReportMemoryLeaksOnShutDown property to true in your project file.

begin
  ReportMemoryLeaksOnShutdown := true;
  Application.Initialize;

If you forget to free an object you will get an unexpected memory leak exception when you close your application.

memleak

This is nice, however we always release allocated memory, don't we?;-)

Although it is nice to know that you leak some memory the messagebox does not help us to find out where it happens. It only reports the type of object, and the spilled memory in bytes.
In the marketplace there are several tools that can be used to signal memory leaks. One in particular, which I am evaluating right now, is Eurekalog.
You can use this tool to catch exceptions and memory leaks in your application. A detailed log file, with call stack, will tell you exactly the location (unit and linenumber) in the source of the unfreed object. Double clicking a line in the call stack opens the unit at that line in the IDE.
Another nice feature of Eurekalog is that you can activate it within your application, so that whenever your user hits an unexpected exception, or memory leak he/she can send the report to you by e-mail or even sent it to your bug tracking system.

The Eurekalog log file for the above memory leak looks like this:
eureka

Although we always free memory, use the try...finally construct, you will leak memory sooner or later. Tools like Eurekalog can help you tracking them down easily. Do you know more sophisticated tools, like Eurekalog, to track down memory leaks?

Friday, October 19, 2007

.NET Enumerator basics

I hereby declare this week as the week of the enumerator. ;-)
Hallvard Vassbotn started this week with an excellent post on using enumerators patterns on your own collections. You should really give this high School enumeration stuff, a read!

The .NET Framework it self offers a lot of basic functionality for enumerators. It is friday so let's take a look on some basics here:

Sometimes it is necessary to let a user pick a value from a enumerator type. For example you want the user to pick some property value of a component, which is enumerator. You could, of course, fill a combox with string values by hand (keeping the order), but in future releases the list could extended, having you to alter your code.

Looping an enumerator
It is easier then to simply loop through the enumerator type. Update! In Delphi win32 this is not possible. This is false! Uli commented that it can in Delphi Win32!, using the Typinfo unit. (See the code in the comments)

In .NET however this is possible using the Enum.GetNames method.
 
In C# you code looks like this:

foreach ( string s in Enum.GetNames(typeof(SeriesChartType)) )
{
   Messagbox.Show(s);
}

the equivalent code in Delphi .NET is:

for s in Enum.GetNames(TypeOf(SeriesChartType)) do begin
   MessageBox.Show(s);
end;

Exists a value?
Check if a enumerator value exists in a enumerator type with the IsDefined method.
Delphi .NET code:


s := 'Point';
if Enum.IsDefined(TypeOf(SeriesChartType), s) then
  MessageBox.Show('Yes')
else
  MessageBox.Show('No');

Conclusion, the .NET framework Enum class, which is the base class for all the enumerator types, adds valueable methods to the basic enumerator types.
More information can be found on MSDN here.

Friday, October 05, 2007

Fooling around with TWebbrowser #4

TWebbrowser and the Enter key
For some reason the Enter key in TWebbrowser does not work. This is very annoying, because users can't use the enter key to submit a form or, even worse, can not go to the next line in a textarea.

Searching the Internet I found two solutions to this problem:

Solution1: Use your applications MessageHandler;
The best solution,imo, is this one provided by SwissDelphiCenter. This solution 'listens' through the application's messagehandler to handle the keystrokes of your webbrowser. (Webbrowser1 in this case).
In my multitab browser I had to tweak this a little bit to give the handler the active webbrowser. (Don't forget to nil the FOleInPlaceObject when you switch TWebbrowser objects).

if AWebbrowser <> ActiveWebbrowser then begin   
FOleInPlaceActiveObject := nil;
Webbrowser1:= ActiveWebbrowser;
end;

This works just fine! Kind of magic to me, but it works.

How to handle popup browsers?
As told in a previous episode of this serie, it is sometimes necessary to invoke the NewWindow2 event to handle popup-browsers. This is typicaly necessary when you need to retain a browser session.

In the NewWindow2 event a new form of you application is popped up modeless to hold the webbrowsers popup. To get the active webbrowser for your messagehandler in this scenario gets a little complicated, because there could be more popups open at the same time, and a popup could have one or more popups. The next solution seems to be more appropiate for that.


Solution 2: Use the Keybd_Event message
Well the Enter key might not work in textarea's, CONTROL + M seems to be doing just what we need, inserting a new line in the textarea.

So we must send a CTRL + M to our webbrowser. Here a solution, as found on Delphi3000, using the Keybd_event function. This function can be used to synthesize keystrokes. So send the CONTROL + M when an enter key is hit and we are done. (Supposing there is only a webbrowser on your popup form).

However there is one side effect with this solution, if you have a textarea and a submit button on your popup webpage, the page will also be submitted if you enter a new line in the textarea. Simple solution for this is to send the CANCEL event after the handling, so this is the code with the extra line (looks a bit messy):



procedure TfrmPopUpBrowser.FormKeyPress(Sender: TObject; 
var Key: Char);
begin
//Don't forget ot set the Keypreview property
//of the form to true!
if (Key=#13) then begin
Key := #0;
Keybd_Event(VK_LCONTROL, 0, 0, 0); //Ctrl key down
Keybd_Event(Ord('M'), MapVirtualKey(Ord('M'), 0),
0, 0); // 'M' key down
Keybd_Event(Ord('M'), MapVirtualKey(Ord('M'), 0),
KEYEVENTF_KEYUP, 0); // 'M' Key up
Keybd_Event(VK_LCONTROL, 0, KEYEVENTF_KEYUP,
0); // Ctrl key up
Keybd_Event(VK_CANCEL, 0, 0, 0);
end;
end;

More info on how use Keybd_event function take a look at the msdn article.

Well in my case it was a little harder to tackle this problem, but it works now just fine. Hope this usefull for others as well.

Thursday, October 04, 2007

.NET Framework sourcecode will be free

According to this blogpost, by ex Borlander Charlie Calvert, Microsoft will ship the source code of the .NET framework with the next Visual Studio release 2008.

He says:
Here is a piece of wonderful news: Scott Guthrie has announced today that we will be releasing the source code to the .NET framework when we ship Visual Studio 2008 later this year!

An option will be made available to allow you to step directly into the source from your own code, so you can see exactly what is happening in the .NET framework. This is exactly what developers need, and it will greatly improve the experience of developing on the .NET Framework .

Scott's announcement.

This is really great news. As Delphi Developers we always had the sourcecode of the VCL (since 1995). Having the sourcecode of any framework is indeed a great learning resource!