tag:blogger.com,1999:blog-90403270364972682902024-03-16T01:10:23.188+00:00Me, Myself and DelphiFinally someone saying the goods and the bads about Delphi 2007...Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.comBlogger67125tag:blogger.com,1999:blog-9040327036497268290.post-11393938101389114092008-05-18T16:28:00.003+00:002008-05-19T22:30:01.907+00:00blog.freeIt's about time that I should assume that I lack the time to spend on this blog.<br /><br />It was fun while it lasted (except for the past few months), but now every weekend that comes and goes and sees me not doing something on this blog is a weekend of pain. This year, my life changed a LOT. I'm no longer using Delphi in my daily routine, I have a beautiful young daughter requiring some attention (not to mention her mother, my wife!), and I also work at a place that makes me spend way too much time traveling back and forth. That will improve in time as I'm due to move closer to home, but, if you factor reason #1 above (no longer using Delphi), then you can see that even with a bit more free time on my hands it will be a pain doing something in Delphi, especially the type of experiments I was doing lately that require repeated (PAINFULLY SLOW) installs...<br /><br />So, rather than feeling bad about each new weekend that I don't get to spend some time on this blog, I opted for the easy way out: delete the blog (I hate sites that stay frozen in time for years in a row!).<br /><br />So, in a couple weeks I'll be deleting this blog. If there's any useful bit of information that you found here and want to preserve/re-use/re-publish, then feel free to do so. It will all be gone on the 1st of June.<br /><br />Goodbye and best of luck to all lasting Delphi users out there.<br /><br />P.S.: This is not a "talk me out of it" type of post. My decision, which has been in the making for quite some days now, is final. This post exists simply because I didn't want you guys and gals finding out that there was no more blog at this location.<br /><br />[EDIT:]<span style="font-style:italic;">GRRR! Damn blogger ate my edits! :)<br />Here I go again...<br /><br />First, thank you all for your kind words. Even though the idea behind this post was to allow everyone some time to copy/paste some stuff, I'll allow this post another 6 months and see what gives by then.<br /><br />Answering some questions:<br />- There's no ";" after blog.free because the following instruction is an "end."... ;) Actually, just kidding as I'm the kind of guy that will add a begin/end pair to a single instruction if/then/else just so to be able to add the ";"... This one was mostly out of being tired...<br />- I'm not using VB nor any MSFT product. What I'm doing currently involves using Flex Builder 3, Python and Javascript (not all in the same project!).<br />- Part II of Thinstalling Delphi: this is the main reason for not being happy with this blog, or rather, the lack of time to do it. As I think I've said before, my previously thinstalled Delphi won't work anymore refusing to even run, and capturing a new one would take quite some time and effort. At this point, even "simply" going through my notes would require some time to understand/test them...<br /><br />Should I find the time and will to do it, I'll give it another try, but I must say that I'm currently a bit disappointed with Thinstall: several previously running thinstalled apps no longer run, which is probably due to some updates to my system, but that's not my idea of making a portable app: having to recapture now and then... As for alternative virtualization products, all those I've tried so far had even worse issues... (Note to self: SELECT ALL, COPY, just in case!)</span>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com10tag:blogger.com,1999:blog-9040327036497268290.post-88297657089551945022008-04-16T22:15:00.001+00:002008-04-16T22:15:57.400+00:00Portable Delphi 2007 for Win32 - Part I.5<p>It's been a while since I started this project and, despite the long period with no posts, it hasn't been forgotten. But a few factors helped to prevent me from completing it as of yet. First I was in bed for a few days from some nasty flue, then I got up before being ready which eventually led back to bed for a few more days, and by then I had a ton of work to catch up with. Factor that with running into some problems with some of my other "thinstalled" applications and not being happy with the Thinstall price tag (which I'm only using because it's registered to the company I'm working for: there's no way I could justify spending 5 grand in a piece of software!), and then you're starting to see the picture. Today I had a bit of time and, after having found another virtualization suite, one that is free for personal use, I decided to give it a spin.</p> <p>Even though it has some design flaws that would make it improper to make a "Portable" Delphi, it could be a nice tool to create a semi-portable Delphi and I may be back to it in a couple weeks or so. But, for the time being, here are the main disadvantages I found in <a href="http://www.altiris.com/Products/SoftwareVirtualizationSolution.aspx">Altiris SVS</a> in a couple hours of use:</p> <p>- Requires the engine to be installed first (admin rights);</p> <p>- Requires the packages to be "imported" which is kind of an Install in that it expands the package over to the virtual redirection folder;</p> <p>- Does not allow an easy way to configure *where* the local changes are stored so it's not trivial to carry your settings with you;</p> <p>- If you want the redir folder to be stored elsewhere other than C:\fslrdr you need to use the command line to manually invoke MSI installer and pass some parameters;</p> <p>- You're "forced" to work in their chosen locale, that is, my Windows XP is English but, because my location and keyboard are Portuguese, I have the regional settings set to Portuguese. If I want the software to be in English as ALL my programs are, I have to overwrite some of it's files, namely copy the .DLLs from the 1033 folder over the ones in the 1046 folder. (I hate dumb programs that try to be smart!)</p> <p>- I also ran into a weird bug: after restoring another semi-clean ghost of my C: drive, and having installed the SVS client (and after the mandatory reboot), I decided to try a "bold" move: double-click an SVS package that I had created earlier. It started to "import" it or so it seemed, but in no time I was rendered with a useless Admin console:</p> <p><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="329" alt="Bugged" src="http://lh4.ggpht.com/Fotos.Madrugas/SAZ6m1j6KEI/AAAAAAAAAT8/rfpUKyFe8tc/Bugged%5B4%5D.jpg" width="400" border="0"> </p> <p>Not even a cold boot sorted it out! I had to restore the ghost image again and re-install SVS again and then I could use the "Import from Archive" option. And I was able to successfully import the VERY same package. Kind of weird of them to create file associations and then have them screw things up so badly!</p> <p>So, I'll keep my original idea and, in the next few nights and in the next weekend I will go back to resume my work on Thinstalling Delphi 2007. It's a shame as Altiris' SVS product was priced just about right: Free for Personal Use! Download license from <a href="http://www.altiris.com/Download/svsPersonal.aspx">here</a> and setup from <a href="http://www.svsdownloads.com/">here</a> if you want to give it a spin.</p> <p><em>BTW: Don't get me wrong on this "negative" feedback: Altiris' product does look promising and it even may have a few advantages (other than the price!) over other similar packages. It's just inadequate for my current project of creating a Portable Delphi. If I get to "play" with this product a bit more, I may come up with a more rounded review focusing also the pluses. It won't be in the next couple weeks due to lack of time and other priorities, such as finishing the Portable Delphi! :)</em></p> Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com8tag:blogger.com,1999:blog-9040327036497268290.post-60537265484322141872008-03-15T19:59:00.001+00:002008-04-07T11:12:35.353+00:00Portable Delphi 2007 for Win32 - Part I<p><em>[EDIT] Even though you can do all listed here, there are a few minor</em> '<em>gotchas'</em> <em>that you should be aware of, so browse through the 2nd part before following this to the letter, especially if you use the command line rather than a graphical tool to delete the folders. <STRIKE>I'm currently typing Part II into Windows Live Writer, so check back in a couple hours if it's not online yet when you're reading this...</STRIKE><B> Unfortunately I ran into an internet problem and then changed my mind and decided to split the work and use WinWord to create a PDF file to upload with the whole start to finish process and only keep the "blah-blah" on the post so that you can more easily follow the process without waving through a ton of blah-blah. But real-life has a way of messing up one's plans! I have been sick for a few days (an annoying flue that kept me in bed and hardly willing to touch a computer). I'm feeling better now and will finish work on this as promised, but it most likely won't happen before the next weekend as I have a lot of work stuff to catch up during the week.</B>[/EDIT]</em> </p><p>Ever wanted to carry your development environment with you on a flash memory stick? Well, using <a href="http://www.thinstall.com/">Thinstall</a> you can, albeit it comes with a hefty price tag of 5.000 USD... Maybe now that VMWare has bought the company they'll wise up and release a cheaper personal version! I would like one, and have e-mailed them already stating that. If you would too, don't forget to bring it to their attention! <em>(Edit: Thinstall is now known as <a href="http://www.vmware.com/beta/northstar/">VMWare Project NorthStar</a>)</em> </p><p>There seem to be some cheaper alternatives, and I even tried <a href="http://www.xenocode.com/Products/Studio/Trial.aspx">Xenocode's Virtual Application Studio</a> (VAS for short) but, even though it has a nice visual interface, it has a few fatal flaws. I couldn't find a way to have multiple entry points and even something as simple as selecting the main entry point is painful with an application that has several thousand files as they use a simple non-typing lookup and they display ALL files to be selected. And if your app (or app combo) somehow has the same exe name in two different folders, then you can't tell them apart in that combo-box... But the main problem against VAS was it failing a simple test: virtualizing ActiveState's Perl 5.8.8... That's something that Thinstall did without a glitch... </p><p>This is a two-part article, but don't worry: this time both parts are already written before publishing the first one! But I also like to tease a bit, so Part II will only come out in a couple days! That and because I took my notes on a text file while doing things and have to get them into WLW for proper formatting! :)<br /></p><h3>Thinstalling (TM) Delphi for Win32 2007 (TM) Professional</h3> <p>Those reading my blog will know that I'm a bit anal about files and disk space in my computer: I'm a software developer (among other things), so I like to be in control! It is <strong>me</strong> and not the machine nor the OS or any given application that should be in control of what goes on on <strong><u>my</u></strong> computer...<br /><br />In light of that, I have a plethora of small and some not so small utilities that I have in a "ready-to-run" state on a different partition, so that, after a fresh install, I can run those immediately. I also use Delphi (currently the "2007 for Win32" version) and if you couple all that with the lousy installer and/or lousy install script that Delphi ships with you can understand why I have targeted it a few times before.<br /><br />I also hate the way my system gets noticeably slower as I add programs. That's no big surprise: the big junkyard of Windows, usually known as Registry, easily starts to hold a gazillion of entries slowing it down. Add Windows Installer to the mix (and very few major-named products these days use an installer that is <strong>not</strong> based on MSI technology) and you can see where all this goes...<br /><br />MSI technology is one of those nice-in-theory concepts with all it's self-healing that allows a "regular Joe" to keep running, say, Microsoft Office, even after he blissfully deletes some required folders because upon running an office application it will detect that some files are missing and will re-install them. Now, this is bad news for those like me that like to tweak things. Something as simple as deleting some readme's in 30 different languages will trigger the self-healing process and next time you run your app, they'll be back in place... Also, messing up with the MSI files left behind on your disk will usually result in bad news, from missing application icons (why on earth don't they use the proper .EXEs for the shortcut icons?), to more serious problems with self-healing kicking in and asking for original media to put things back there and you not being able to run the app until you please the installer... </p><p>So, I decided to try a new angle and this time I decided to experiment with an old tool but one which I only recently got in contact with: Thinstall. In a short sentence, it's VMWare for single applications, that is, it's a virtualization system that allows you to run applications without installing them first. Just double click a "simple" executable file and it will run as if you had installed it on your machine. </p><h3>So, what are the pluses and minuses of Thinstalling applications? </h3> <p><strong>+ No more re-install whenever you switch machines or re-format your C: drive or reset it to a "working" ghost image;</strong><br />- You <strong>do</strong> need to re-activate when you switch machines; (<em>that's an area where those using pirated and cracked versions have an edge over us, licensed users, but that's the price to pay when companies don't trust their customers and with MSFT setting the way, other companies keep following like lambs...</em>)<br /><strong>+ You can run Delphi 2007 for Win32 from a 1 GB USB flash drive <u>even on a machine with NO .Net installed and from a restricted guest account</u>;</strong><br /><strong>+ You can run it from a network share with no concurrency problems;</strong><br />- Updating a "Thinstalled" app requires a bit more work (more on that on Part II);<br />- By default, a thinstalled program will have R/W access to "My Documents" and "Desktop" only: every other file/folder accessed, if changed, will be modified in a local copy on a "sandbox"; you can however configure per folder/drive which ones will be writeable or not. Or you can configure your thinstalled app to run in "merged" mode, but that can be tricky if the host computer has a similar version of the app installed.<br /><strong>+ Thankfully, network and removable drives are used R/W by default so if your files are not on a local disk, you don't need to make further changes to modify them.<br /></strong>- You can't Thinstall apps that install device drivers, such as PalmOne apps or a Virtual CD/DVD emulator or even some Anti-Virus.<br /><strong>+ You <u>can</u> Thinstall applications that install and depend on services as those will be virtualized and started as well when you run your app.</strong> </p><p>In my current setup, using a 4 GB flash drive, I can fit pretty much everything I need, being 1 GB for a ghost image of Win XP SP3 RC2 with nothing but Win XP + AV + , another one for Delphi 2007 and still have 2 GB left for other thinstalled applications and some data files. This allows me to be back in a working condition within 10 minutes, even if something seriously messed up my hard disk big-time...<br /> </p><h3>So, how does one get to Thinstall Delphi 2007 for Win32? </h3> <p>After you get hold of a copy (you can get a trial from Thinstall's website), you do the following: </p><p>0 - Start with a CLEAN machine: I recently re-installed my C: partition with Windows XP SP2 and, after changing some settings, I proceeded to make a ghost of that partition to a bootable 2 GB USB flash disk (only uses less than 600 MB after a bit of tweaking). Using a CLEAN machine is important as is choosing the "oldest" one, that is, if you plan on running it on Windows 2000 and XP, don't use XP for the CLEAN machine as it may already have some files that the 2000 will not and those won't be installed and thus won't be captured. </p><p>0b- It's also VERY important to do it all in one go and refrain from using non-related programs, such as surfing the net or doing downloads or even cleaning up your temporary folders: whatever you do may get added to the thinstall project and needlessly clutter it. </p><ol> <li>Run "Setup Capture" and do the pre-install capture.<br /></li><li>Install Delphi (including .net runtime and SDK); as for the shortcuts location, I used the option for "All Users" so it would not clutter my relocated "My Documents".<br /></li><li>Launch and activate (if you want the install to be pre-activated, e.g., you're the only one using it); if you don't activate, when you run it you'll have 30 days to do it later, although I believe, but haven't tested, that those 30 days start counting from the day you INSTALLED it and not from the date you first run the Thinstalled version.<br /></li><li>Configure any settings and/or install components and/or install updates.<br /></li><li>Run "Setup Capture" and do the post-install capture.<br /></li><li>Select the "shortcuts" to create and main package name. When you Thinstall an application, you create a single executable file but you can have alternative "entry points" into that file to run other applications that are part of the same capture. For instance, you can have an independent shortcut for running the Help Documentation without first launching Delphi. These are dependent of the "main" package where all the files/registry settings are stored. On my system, and for some reason (GUID conflict?), it suggests to store the capture in "ATI - Software Uninstall Utility". I opted instead to name the capture folder "Delphi 2007".<br /></li><li>Wait a few minutes while it copies over 31.000 files using 3+ GB for my Professional SKU full install.<br /></li><li>On my system, it failed to copy "C:\Documents and Settings\LocalService\NTUSER.DAT" and "C:\Documents and Settings\NetworkService\NTUSER.DAT": just ignore as those should not be copied anyway... This may be a symptom of me not following step 0b! :)<br /></li><li>IMMEDIATELY SAVE this captured installation, that is, save the "Delphi 2007" sub-folder inside the Captures folder: this will be needed later if you want to upgrade your installation. I copied it to my external hard-drive and named it "Delphi 2007 (Full)" to distinguish from a copy that I'll make later after the tweaking is done.<br /></li><li>Now we can start tweaking the thinstallation!<br /> </li></ol> <h3>Tweaking the Thinstallation </h3> <p>You can do the remaining process on any machine: all you need is access to the thinstall folder and respective Capture sub-folder where you stored your "Delphi 2007" capture. I opted to use the same machine as I will quickly restore it to a clean state by booting from a flash drive and running ghost from there. </p><ol> <li>Go to your "Delphi 2007" capture folder and open up "Package.ini";<br /></li><li>Uncomment (remove the starting ";") the "CompressionType=Fast" line and comment the other one (";CompressionType=None"); this will instruct Thinstall to use a quick compression when creating this application. Whenever in doubt, check Thinstall's online help file for available options.<br /></li><li>Edit the "Sandbox=" line and use a descriptive name. (I used SandboxName=Delphi 2007). Whenever you run a Thinstalled application, any changes to registry and files that are not in the "merged" folders/keys will be saved in a local sandbox. By default, that is in your current user's Application Data\Thinstall\<sandboxname> folder, so, in a typical Win XP install, with a user named Joe and the suggested sandbox name above, this will be "C:\Documents and Settings\Joe\Application Data\Thinstall\Delphi 2007". It is possible to configure the application to clear this folder on exit, but you can also do a more interesting thing: if you create a "Thinstall" folder in the same place where you have your Thinstalled application, that folder will be used to store the Sandbox. This is particularly useful to do when running an application from an USB flash drive as in this way, not only your settings are not stored on the local computer, they will "travel" alongside the application on your flash drive.<br />3b- I like to keep my apps in the same drive, a partition of my HDD and a copy of everything on a 4 GB flash drive. In both cases, a neat way to keep all your settings (read: sandboxes) nicely grouped in one place is to add the following line next to the previous one:<br />SandboxPath=LocalSandbox\..\..\..\..\.Settings<br /> This way, and as long as your apps are not stored more than 3 levels deep, all the sandboxes will be created under the .Settings folder in the root of the drive where the applications are. So you can have something like:<br /> X:\Multimedia\Image\Image Editing App 1.exe<br /> X:\Multimedia\Image\Image Editing App 2.exe<br /> X:\Multimedia\Audio\Audio Editing App 1.exe<br /> X:\Dev\RAD Studio 2007\Delphi 2007.exe<br /> and, assuming the Sandboxes use the same name as the executables, you'll have the sandboxes created like this:<br /> X:\.Settings\Image Editing App 1\<br /> X:\.Settings\Image Editing App 2\<br /> X:\.Settings\Audio Editing App 1\<br /> X:\.Settings\Delphi 2007\<br /></li><li>At this point, I did my first "build" which is as simple as invoking the BUILD.BAT file: 1 hour and 22 minutes later (on a 3 year old laptop!), I had a 2.000.782.941 bytes "Delphi 2007.dll" file along with a few .exe entry points for a total of 1.86 GB. Of course, this includes at least the huge 600 MB file with the .NET framework SDK install files. We'll get rid of those soon!<br /><br />4b- Don't worry about two things: the app won't show the proper icon (we'll use a workaround for an explorer bug soon), and it may take a LOAD of time launching (we'll get to that fix soon too!). If you want to test it out quickly, just launch something like the Command Prompt or the Documentation.<br /></li><li>Thinstall captures are very easy to process: 3 "registry change" files are created containing all the registry changes to HKLM, HKCU and HKU; several "virtual" folders are created such as "%desktop%" which equals the current user's desktop folder and some %drive_x% folders for each drive where changes where made other than in one of the "standard" folders, that is, if the program only makes changes to, say, "C:\Program Files\CodeGear...", you will see no %drive_c% folder created, but if you change the default install to, say, "C:\Delphi2007", then you'll see a %drive_c%" folder with whatever was created/modified there.<br /></li><li>We can safely get rid of uninstall files(*) as there's no point in uninstalling stuff from a Thinstalled app: even though the changes would be recorded in the local sandbox, and it would appear uninstalled, you'd save nothing by doing so and by deleting the sandbox, it will revert back to the "default" state. Thinstall also already ignores changes to some self-healing registry keys, so you can remove stuff without being prompted with a "re-install".<br />(*) As we'll see in Part II, there are some exceptions, with Delphi being one of them!<br /></li><li>With that in place, let's delete (you <strong><u>DID</u></strong> make that full copy already, didn't you?!) the following folders/files:<br /> - %ProgramFilesDir%\Microsoft Visual Studio 8\Microsoft .NET Framework 2.0 SDK - ENU (569,8 MB)<br /> - %SystemRoot%\Microsoft.NET\Framework\v2.0.50727\Microsoft .NET Framework 2.0 (76,4 MB)<br /> - %SystemRoot%\Microsoft.NET\Framework\v2.0.50727\Microsoft Visual J# 2.0 Redistributable Package (15,6 MB)<br /> - %SystemRoot%\Installer (93,9 MB - this was unrelated to Delphi 2007 and probably because I somehow ran something else: I've had this capture on "hold" for a couple days...)<br /> - %Common AppData%\{6AF0EFC6-B937-4704-A430-319EB93F4C12} - Delete all sub-folders but leave the files as they're needed for the "Check for Updates" option. (423 MB) This one will be in %Local AppData% instead of %Common AppData% if you used the "Just for me" shortcuts option when installing.<br /> - %Common AppData%\{135F413C-658B-4923-B950-5F2B786BC8DA} (341 MB - Help update setup files)<br /> - %Profile% (nothing useful)<br /> - %Common Programs% and %Desktop% - These hold the shortcuts as created by the installer, but we'll use a different set<br /> - HKEY_USERS.txt (on my system, there's only a handful entries and none Delphi related, probably for me breaking step 0b!)<br /></li><li>Now let's open up Package.ini and fix a few more things:<br />- Fix the broken Icon for "Delphi 2007.exe". Find the section [Delphi 2007.exe] and duplicate it. Now do a find/replace (on the whole text file) finding "Delphi 2007.exe" and replacing with "Delphi 2007.dll". Next, change one of those two sections to read [Delphi 2007.exe]. You'll need a few more changes so just check that they look like this:<br /><span style="font-family:Courier New;"><br /><strong>[Delphi 2007.exe]<br />Shortcut=Delphi 2007.dll<br />Source=%ProgramFilesDir%\CodeGear\RAD Studio\5.0\bin\bds.exe<br />CommandLine="%ProgramFilesDir%\CodeGear\RAD Studio\5.0\bin\bds.exe" -pDelphi<br />Shortcuts=%Programs%\CodeGear RAD Studio<br /></strong></span><span style="font-family:Courier New;"><br /><strong>[Delphi 2007.dll]<br />ReadOnlyData=bin\Package.ro.tvr<br />Source=%ProgramFilesDir%\CodeGear\RAD Studio\5.0\bin\boreditu.dll<br /></strong><br /></span>The "problem" you fixed is that Explorer will try loading the whole .exe file in memory to show the icon, and with an .exe several hundred MBs it will fail. We trick it by storing the "bulk" of the information in a .dll or .bin or .dat or whatever non-exe file and then adding a smaller shortcut to Delphi 2007.exe, as per the Thinstall help section on this topic.<br /><br />- You can cleanup quite a few more entries in here, or just leave them with Disabled=1 so they won't have shortcuts created alongside with the main executable. I left the following entry points enabled:<br /> <em>Check for Updates, Delphi 2007, RAD Studio Command Prompt, RAD Studio Documentation, Rave Reports.<br /></em> </li><li><em></em>You may want to find and delete all the "Icon=" lines as they force some applications to use an icon stored in an MSI instead of the one in the EXE and deleting the Install cache will get rid of the icons.<br /><em>[EDIT]In order to keep the RAD Studio Command Prompt and the Documentation icons, move those two *.ICO files elsewhere or copy them from the "full" version if you have already deleted them from step 7 above and update the Icon= line accordingly. You can, for instance, name them RAD Studio Command Prompt.ico and Documentation.ico and place them straight in the project root directory so that it's clear what they're used for.<br />[/EDIT]</em></li></ol> <p><br /></p> <ol> <li>Also, while you're at it, check the lines with "Shortcuts=" (notice that it's PLURAL Shortcut<strong><u>s</u></strong> with an S at the end: not to be mistaken with the similar but different meaning option Shortcut!).<br />In my install, I set all the shortcuts into a Thin\genre\app type of folder, for instance, I use <span style="font-family:Courier New;">Shortcuts=%Programs%\Thin\Dev\Delphi 2007</span>, so that all shortcuts created (for the sections that don't have Disabled=1), will be stored in a Thin -> Dev -> "Delphi 2007" folder. (More on that on Part II).<br /></li><li>The speed problem seemed to go away as soon as the "main" executable file dropped in size: didn't test to see if it was related to being over 2 GB of uncompressed data or to having a few huge files in there, but it works ok in a 1.7 GB uncompressed version as well as in this 1 GB compressed one...<br /></li><li>Now you can re-build by simply invoking the batch again. On the same machine as above, and because Thinstall caches the files from the previous compilation, it took only 10 minutes to generate the brand new 1.032.472.412 bytes file. This means that, together with the few extra shortcuts or alternative entry points, it now uses up only 984 MB, so it perfectly fits on a 1 GB flash drive. (And we'll trim that further in Part II).</li></ol> <p>That's all for now. In Part II, we'll tweak a lot more by removing the .net related help content. I will also explain how to update your Thinstalled "Delphi 2007.exe" file so that you can incorporate patches, add/remove/update some components or simply modify default settings. Finally, I'll show you how easy it is to have the proper file type associations so that you can simply double-click an *.dpr file and open up your Thinstalled Delphi. Until then, get your own <span style="color:#ff0000;"><em>(30 day trial of Thinstall)</em></span>* and start playing!</p> <p><em>* EDIT: Thanks to Xsintill for pointing out the <a href="http://www.vmware.com/beta/northstar/">VMWare NorthStar beta</a> (which is essential the full Thinstall project) but has two things better than the Thinstall trial: 1) lasts until 1st of June 2008 (roughly 70 days from now); 2) The whole registration process for the trial is automated and less restrictive in the choice of e-mails. So go grab that beta and start playing...</em></p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com38tag:blogger.com,1999:blog-9040327036497268290.post-10632283269250462262008-01-26T19:29:00.000+00:002008-01-27T01:07:17.612+00:00More Disk Space Tweaking...<h2><font face="Arial" color="#ff8080" size="2"><em>UPDATE 1: DO NOT TRY THIS! Even though everything is working ok on my system, I've just noticed a shortcut icon problem that I believe is related to the order I've done something. I'll have to test it a bit more and will update this post where needed to prevent that from happening but it may take a couple days before I update the post!</em></font></h2> <h4><font color="#ff0000" size="2">Update 2: Apparently it's Windows Installer that is to blame. Not only it completely ignores the junction, it goes even further: deletes the junction (causing all contents to be lost!) and creates a new INSTALLER folder in your Windows subdirectory. So, this particular folder CANNOT be moved or the next time you use msi installer (which is just about any installer or patcher these days), you'll LOSE all that was transferred.</font></h4> <h4><font color="#ff0000" size="2">It's always "fun" to see Microsoft NOT playing by their own book!</font></h4> <p>Or, how to keep your C: drive mean and lean and still don't throw away those lengthy patches and cached install files...<br>This is not entirely related to Delphi as the techniques used here are more general and thus you can extend this to your own liking. It is however triggered by the fact that I hate to see wasted space on my C: drive, which, as I've told you before, Delphi's current installer likes to do! :)<br>In short, you'll learn how to relocate some huge folders to another partition or even another hard-disk. This is especially useful for temporary or cache folders as those serve no useful purpose 99,99% of the time but still use up disk space.</p> <p><font style="font-weight: bold; font-style: italic" size="4">Theory</font><br><br>The whole process revolves around Windows XP and NTFS formatted partitions: you can create junctions, which are links to folders or whole disks and access those as if they were native folders on another partition. For instance, you could relocate <font face="Courier New" color="#000080">C:\Documents and Settings\All Users\Application Data</font> to <font face="Courier New" color="#000080">D:\MyData</font> and whenever a program tries to access the first folder it is in fact accessing physical data from the MyData folder in drive D:<br><br>To ease up the process, I created a small batch file in <a href="http://www.jpsoft.com/4ntdes.htm">4NT</a> (sorry, but I don't do CMD in years and don't feel like going back!). 4NT has a nice little command MKLNK (and also a newer one MKLINK which is *NOT* what we'll use, so just keep it in mind that there are two very SIMILAR but DISTINCT commands!). The MKLNK command allows you to take advantage of mount points and create/delete them. In the end of this post, I'll list the whole batch file I used. As you can see, using ALIASes and a few 4NT variables and functions makes the whole batch a lot better than if I were to try it out using CMD only!)<br><br>Now, I'm sure that there is a MKLNK-alike utility or two around, even though I haven't searched for any, so feel free to ignore the batch and try doing the commands on your own, although you'd probably be doing yourself a big favor by actually trying out 4NT! ;)<br><br><font size="4"><font style="font-weight: bold; font-style: italic">Limitations</font></font><br><br>As mentioned in the batch file itself, which you can download from <a href="http://www.box.net/shared/nvpnaaog80">here</a>, you need to be aware of the following:</p> <ul> <li>Non-English versions of Windows XP may use different names for Application Data and Local Settings; <li>You have to edit the SET %RootFolder= line to set your own root folder. I used T:\Patches but you can use anything else (and even modify the batch to spread things around multiple folders instead of sub-folders of this one) <li>This batch file is a first version. In order to keep things simple, it does NOT check for available free space on the target folder but it does warn at start that it doesn't do that and that you SHOULD make sure you have enough or else you risk being left with some stuff moved and other not quite so... I do believe, but have NOT tested, that it should be able to resume from where it left if you run out of free space and then run the batch again, but, I repeat, I have NOT tested that!</li></ul><font size="4"><font style="font-weight: bold; font-style: italic">Let's get busy!</font></font><br><br>So, let's start digging into the batch file:<br><br><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="340" alt="01-24" src="http://lh4.google.com/Fotos.Madrugas/R5us3LDoUzI/AAAAAAAAATM/Nqy6gNkUJgo/01-24%5B5%5D" width="644" border="0"> <br><br>You should edit line 5 and, if running on a non-English OS, change line 9 and comment lines 15 to 17.<br><br>Line 20 defines an alias to test for the existence of a folder name, create it if not found (creating parent folders if needed) and then changes to that folder. It's not exactly needed here as it's only used in one place, but I copy/pasted it from my aliases file.<br><br>Line 23 defines another alias to echo a blank line, then echo the passed parameters slightly indented.<br><br>The %+ symbol equals "whatever command separator is configured on this system". 4NT allows several commands to be executed on a single line, which is useful, among other places, in aliases.<br><br><font style="color: rgb(255,0,0)"><insert image="" 30="" here=""></insert></font><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="116" alt="25-30" src="http://lh4.google.com/Fotos.Madrugas/R5us4LDoU0I/AAAAAAAAATU/xUmco10MmBM/25-30%5B4%5D" width="644" border="0"> <br><br>Now we get to the main alias, the one doing most of the work in line 30.<br>Here we test if the 1st parameter is already a junction: if that's the case, then the "TRUENAME" (which is a 4NT function that returns the actual full path and "sees" through junctions, substs, net shares and symlinks) and we compare that to the "FULL" name, that is, the name after expanding any % variables and processing any ..\ or drive aliases. If they're equal, then no junction is in place.<br>Here's an example to make it clearer:<br>Imagine that:<br> <ul> <li>%windir% equals C:\WINDOWS <li>%windir%\$hf_mig$ has been redirected to T:\Patches\$hf_mig$ <li>%1 equals %windir%\system32\..\$hf_mig$ (this is intentionally complicated to illustrate)<br></li></ul> <p>ECHO %@TRUENAME[%1] would return T:\Patches\$hf_mig$<br>ECHO %@FULL[%1] would return C:\Windows\$hf_mig$<br><br>If the two match (which is false in this case), then no junction or subst is in place. Seeing that you can only SUBST a whole drive letter and not a folder, it is assumed by the batch that if it fails you already have a junction in place and you get a warning (the ELSE part). If the two strings match, then no junction is in place so it MOVEs the source to the destination, showing only /Totals instead of all files moved, moving /Hidden files, not complaining on /Errors, and moving whole /Subdirectories. Finally, the junction is created to "fake" the system into believing that the whole folder exists but it now points to a different drive.<br><br><font style="color: rgb(255,0,0)"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="228" alt="31-44" src="http://lh3.google.com/Fotos.Madrugas/R5us47DoU1I/AAAAAAAAATc/F6eWL1c64r0/31-44%5B4%5D" width="644" border="0"> </font></p> <p>Line 36 shows a message box prompting the user to acknowledge that the batch will NOT check for free space and asking to proceed.</p> <p>Lines 39-41 stop some services that interfere with moving some of these folders. If you add to the list below, you should first use an utility like <a href="http://technet.microsoft.com/en-us/sysinternals/bb896655.aspx">HANDLE</a> from SysInternals to check if some program or service is keeping that folder or anything inside open and add the service to the list and maybe even use <a href="http://technet.microsoft.com/en-us/sysinternals/bb896649.aspx">PSKILL</a> to terminate the application if it's not a service. <em>(Edit: on checking SysInternals website for the links to add here, I noticed a </em><a href="http://technet.microsoft.com/en-us/sysinternals/bb896768.aspx"><em>Junction</em></a><em> utility that you can use if you don't/can't/won't use 4NT!)</em></p> <p>Line 43 creates the root folder if needed.</p> <p><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="242" alt="45-59" src="http://lh5.google.com/Fotos.Madrugas/R5vXQbDoU4I/AAAAAAAAAT0/W3ujP_1pfzQ/45-59%5B5%5D" width="644" border="0"> </p> <p>This is the "bulk" of the work, relocating several folders from my system to the cache folder. Pretty self-explanatory (ignore the color bug in some of the lines: that's <a href="http://www.ultraedit.com/">UltraEdit</a> not syntax highlighting BTM files properly!)</p> <p><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="228" alt="60-75" src="http://lh3.google.com/Fotos.Madrugas/R5us67DoU3I/AAAAAAAAATs/k7Jo2e1gcvA/60-75%5B9%5D" width="644" border="0"> </p> <p>Finally, I also disable (/CACHESIZE=0) and remove existing entries (/PURGECACHE) in the dreaded %windir%\dllcache folder. You may want to remove or comment out this line if you rather keep half a gigabyte of duplicate dlls on your disk.</p> <p>Lines 69-75 remove ALIASes and SETs used by this batch. Not really needed, but I like to clean up after myself! :)</p> <p>And that's all for now. There are more folders that can be safely added to this list, and, on my system, this saved me 2.5 GB worth of C: space. <em>EDIT: Even not counting Installer, I still save 1.6 GB worth of data...</em></p> <p><strong><em><font size="4">End Notes</font></em></strong></p> <p>If you're thinking of doing this to, say, the user profile directory, you'll need to do it from another account and not have logged that account in the current work session. But I would advise you NOT to do it! I once did it, and even in a more "crude" way requiring messing around with the registry, but then I found that doing it saves a LOT of trash! So, upon restoring a working C: image, I'd have my profile all set with all the trash accumulated from all the programs installed/removed/changed.</p> <p>You can download the batch file from <a href="http://www.box.net/shared/nvpnaaog80">here</a>. (Yes, I know I've linked it above, but it's easier to find it here if you come back later!)</p> Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com0tag:blogger.com,1999:blog-9040327036497268290.post-89874051851398566422008-01-20T23:39:00.001+00:002008-01-20T23:39:47.992+00:00Help needed with PDF Processing Library...<p>After two days of searching, clicking through hundreds of links, downloading tens of files, trying, browsing, etc, I decided it was about time to give up and ask for help!</p> <p>I need to process some PDFs, mostly "black-and-whitening" them, that is, converting color boxes and text into black and white. It's not the same as "printing" in black and white though, as I want to replace boxes filled with some color with ones with no color fills and change the corresponding white or light colored text with black text.</p> <p>Example:</p> <p>From this:<img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="161" alt="Source" src="http://lh6.google.com/Fotos.Madrugas/R5Pbv5xbg-I/AAAAAAAAAR4/ygknKtDkBFE/image%5B9%5D" width="200" border="0"> to this: <img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="161" alt="Destination" src="http://lh4.google.com/Fotos.Madrugas/R5PbwZxbg_I/AAAAAAAAASA/r6YKCGi5cMg/image%5B8%5D" width="200" border="0"> </p> <p>I'd like to do this in Delphi, but I can do in a million other languages such as Perl, PHP, Python, Java, C# or whatever. I have one restriction though: the library has to be either free or open-source, but this restriction can be waived if there's nothing free or open-source that I can use to solve the problem...</p> <p>Does anyone know of a library that will allow me to do that? Open a PDF file, loop through all the objects and change characteristics as I see fit, and finally saving the edited file</p> <p>If you know such a library/tool, please leave a comment... Thank you.</p> Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com4tag:blogger.com,1999:blog-9040327036497268290.post-22842338575480756202007-12-10T21:00:00.001+00:002008-01-25T01:29:18.975+00:00Even slimmer Delphi for Win32 2007<p><a href="http://lh4.google.com/Fotos.Madrugas/R12o9GDSGaI/AAAAAAAAARk/ayjXv4nIzJ4/Slim%5B6%5D"><img style="border: 0px none ;" alt="Slim" src="http://lh4.google.com/Fotos.Madrugas/R12o-GDSGbI/AAAAAAAAARs/x_fD9U7SS-g/Slim_thumb%5B4%5D" align="left" border="0" height="178" width="204" /></a> Following on previous posts, I decided to remove the Windows SDK documentation from my Delphi 2007 installation. The main drive was for the added space: with those 250 MB less I would be able to fit the whole C: into a compressed ghost image file with less than 2 GB and that's with Windows XP SP2 + Office 2003 + Delphi 2007 + quite a few more programs and updates.</p> <p>Why is it so important to be < 2GB? Because I can easily upload that single file to any FTP server without worrying about the server or client being unable to FTP files bigger than 2GB; because I can copy that to any disk partition/external drive without worrying about the 2GB FAT 32 limit; because it's a single file to keep track of, without risking to have no backup at all just because somehow one of the multi-part files didn't get copied for whatever reason and finally, because I can now fit the file into a 2 GB usb flash drive.</p> <p>So, rather than just delete the files, I decided to check out the Help registration files and modify them as well. I needed to modify 3 files: h2reg.ini, Master.HxT and RADStudioFilter.xml (get all 3 from <a href="http://www.box.net/shared/du2seak0s4">here</a>).</p> <p>What did I gain?</p> <ol> <li>250 MB less of disk space;</li> <li>Going from 14 to 4 seconds on the first help call of each session;</li> <li>Getting less extraneous results;</li> <li>Being able to now fit my whole C: drive onto a single < 2GB file.</li></ol> <p>What did I loose?</p> <ol> <li>Basically, the Dinkumware, C++, Delphi.NET and Windows Platform SDK help.</li></ol> <p>Of these, the most "troublesome" will be the PSDK, but that can be easily accessed online directly from <a href="http://msdn2.microsoft.com/en-us/library/default.aspx">MSDN Library</a>, and has the advantage of being more up to date...</p> <p>How did I do it:</p> <ol> <li>Go into your "%ProgramFiles%\CodeGear\RAD Studio\5.0\Help\Doc" folder;</li> <li>h2reg -u</li> <li>copy the supplied files over the ones with the same name there;</li> <li>h2reg -r (or run the install_and_view.cmd file that is already there)</li></ol> <p>Now you can delete the PSDK and Dinkumware folders.</p> <p>If you want to "play safe", backup the whole DOC folder to a CD or external drive, should you want to go back. To undo, h2reg -u, replace the folder, run the install_and_view.cmd.</p> <p>BTW: disregarding the .NET pre-reqs, Delphi 2007 for Win32 uses around 400 MB of my disk space now, which is just about right for me!</p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com6tag:blogger.com,1999:blog-9040327036497268290.post-14155968015218625802007-12-10T14:31:00.001+00:002007-12-11T18:29:14.829+00:00Get rid of another 343 MB...<p>If you installed the <a href="http://cc.codegear.com/item/25163">Help Update</a>, be aware that you now have an extra cached (yes, duplicate!) 343 MB worth of data in <em>C:\Documents and Settings\All Users\Application Data\{15EDF4CD-698A-4E52-8278-2E25143AD95B}</em> (change to wherever you have your user profiles and I don't know where that is in Vista, but if you scan your HDD for the folder named {15EDF4CD-698A-4E52-8278-2E25143AD95B}, you should find out easy!</p> <p>Yep, that's CG again thinking that they ought to know better than us, developers, and treating us like "dumb users" and caching stuff without even asking for our consent...</p> <p><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="84" alt="343MB" src="http://lh3.google.com/Fotos.Madrugas/R11Np2DSGZI/AAAAAAAAARc/f79QNrC4Fbw/image%5B4%5D" width="399" border="0"> </p> <p>For those thinking "when will this guy stop complaining about this?": you know the answer! When CG stops DOING it! :) I can understand some lack of choices for "normal" software, where the users may need to be protected of themselves, but as a developer, I like to be in control of my machine, rather than have it control me, or in this case, rather than have software waste disk space for no good reason other than because someone was lazy when creating the installer...</p> <p>Sure, disk space is cheap, but what happens when you try to <strong>BACKUP</strong> that "cheap" disk space? You're left with no other choice than backing up to ANOTHER disk which has huge drawbacks such as now allowing you to (easily) keep a backup outside your installation so you can quickly recover from a building fire or something... And most 1-man shops just can't afford a fire-proof vault that can keep data backups safe because those things are just too expensive, not to mention bulky and heavy...</p> <p><em>EDIT (for those that don't read the comments!): </em><a href="http://blogs.codegear.com/chrispattinson/"><em>Chris Pattinson</em></a><em>, from CodeGear, warns about not being able to run future help patches and needing a full re-install should you delete this folder, so, you can do two things if you still need the space:</em></p> <blockquote> <p><em>1) Back up the folder to a CD/other disk prior to removing it;</em></p> <p><em>2) If you have already deleted the folder, simply install on a Virtual Machine and copy the folder from there. Or, should you have multiple machines with Delphi 2007, just copy the folder from another one. As long as it's added to the same place, you should be fine.</em></p></blockquote> Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com8tag:blogger.com,1999:blog-9040327036497268290.post-70185796617847156792007-11-29T20:55:00.001+00:002007-11-29T20:55:18.172+00:00Delphi 2007 SP3 - Some quirks<p>On my <a href="http://memyselfanddelphi.blogspot.com/2007/11/delphi-2007-improved-help.html">Help Tests</a>, I ran around some minor quirks and I decided to blog about them as well! (Whoa: 3 whole posts in one day? Don't worry, that's probably 3 more months without posting so you'll have enough time to recover!)</p> <p>Don't get me wrong, <em>these are minor quirks</em>, but it's also the 4th release of Delphi 2007 for Win32 (Release, SP1, SP2, SP3), so these should have been caught and dealt with by now, unless the <em>quality control processes are seriously flawed</em>... And before someone else goes "Oh, but the product is VERY good if this is all you can say about it", let me just point out that, no, this is not all (I've placed over 40 QC reports back when I did care about doing it), these are just those that <strong>immediately</strong> jump on you <strong>seconds</strong> after you start using the product, which doesn't give a good idea about the overall product quality... <strong><em>First impressions usually take longer to disappear...</em></strong></p> <p>1) Even selecting "Just me", the shortcut for the RAD Studio Documentation is installed for All Users.</p> <blockquote> <p>In all honesty, I can't say whether this is a bug from the default SP3 install or caused by the Help Update. In either case, it should have been child's play to both detect and fix this, so there's no real excuse for letting something as simple as this slip through...</p></blockquote> <p>2) Minor toolbar sizing errors:<br><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="169" alt="Toolbars" src="http://lh6.google.com/Fotos.Madrugas/R08nLdVd-vI/AAAAAAAAAQ8/dGTtGEnzWio/Toolbars4" width="819" border="0"></p> <p>3) Personality Icon not showing (it appears to show only when a project is loaded, which is a bit odd for a single personality product)<br><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="178" alt="Personality" src="http://lh5.google.com/Fotos.Madrugas/R08nMNVd-wI/AAAAAAAAARE/oqUPAB5KuZo/Personality4" width="813" border="0"> </p> <p>4) <strong>Help Improve Visual Studio</strong>. WHY? If you buy a Volvo, will you get a form to fill out and return to FORD about how pleased you are with their engine? It doesn't make sense and for a team of developers, it shouldn't be hard to determine what registry key is needed to stop that from showing. Creates a wrong impression, when one does NOT buy Visual Studio and instead opts for buying a CodeGear product and then sees that "Help Improve Visual Studio"!</p> <p>5) What's with this dull launch screen? So much space and the only thing that changes is a couple lines at the bottom? I used to like the previous launch screen better. Maybe it gets "filled" when you have some optional dotNET "modules", but as it is, it's plain dull...</p> <p><a href="http://lh4.google.com/Fotos.Madrugas/R08nM9Vd-xI/AAAAAAAAARM/bsAm9B6YPOY/Dull2"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="204" alt="Dull" src="http://lh6.google.com/Fotos.Madrugas/R08nNdVd-yI/AAAAAAAAARU/y0cTJHw1Ouw/Dull_thumb" width="203" border="0"></a> </p> <p>Like I said above, all <strong>minor quirks</strong>, but also all <strong>first wrong impressions </strong>with a product...</p> Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com7tag:blogger.com,1999:blog-9040327036497268290.post-47897201154361039632007-11-29T20:44:00.001+00:002007-11-29T20:44:33.234+00:00Delphi 2007 Improved Help (?)<p>If you recall from previous posts (yes, I know it has been a while, but I've been busy!), I was frankly disappointed at the so-called "Improved Help".</p> <h3>The major flaws</h3> <p>Back on release of Delphi 2007 for Win32, the major flaws I found were the following (listed in no particular order, but numbered for easier reference):</p> <ol> <li>Crashing the IDE when requesting help on a menu; <li>Failing to retrieve help for common Pascal/Delphi keywords; <li>Giving "precedence" in searches to results pertaining to VB, VC++, Anything else under the moon and, in the last spot, Delphi; <li>Taking up a huge amount of space with non Delphi for Win32 help contents; <li>Using an Help engine that would consistently remain in memory leaking resources; <li>Failure to retrieve help for components in forms or giving too many pointless options to choose from;</li></ol> <h3>What has changed on SP3</h3> <p>#1 was solved with SP1, IIRC;</p> <p><a href="http://lh3.google.com/Fotos.Madrugas/R08kmtVd-pI/AAAAAAAAAQM/pruIk8uH_Dk/Help%20on%20End%5B5%5D"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="204" alt="Help on End" src="http://lh6.google.com/Fotos.Madrugas/R08kndVd-qI/AAAAAAAAAQU/77be2p-L-Fo/Help%20on%20End_thumb%5B3%5D" width="180" align="right" border="0"></a>#2 Simple test program loaded from the demo ones. Pressed help on <strong>unit</strong>, <strong>interface</strong>, <strong>uses</strong>. All of these would pop a few options to choose from, but among those was the "correct" one. Then press F1 over <strong>type</strong>: only two options given and neither very useful... <strong>Class</strong>, <strong>procedure</strong>: again a few choices; <strong>private</strong>: a few choices too and among them the "good" one, but the one that I clicked first because it looked as the most promising, took me instead to the C++ reference section. No, that's not C++.net, but rather RAD Studio C++ reference. Odd for a "Delphi for Win32" product. Yes, I know that they have common bases for all their products, but that's THEIR choice and US, END-USERS, should NOT be bothered with that. If I'm programming in Delphi (Pascal), I should NOT need C++ help on my system and certainly not being offered that help when I press F1 on a Delphi keyword... The image on the right shows a list of the choices given when pressing F1 on <strong>end</strong> (but a similar one shows up for <strong>begin</strong> as well)... </p> <p>#3 From the tests above, it appears that this has been nicely worked out: many VC++, VB or J# entries still show up, but usually towards the END of the list, rather than being at the top of it.</p> <p>#4 remains the same and I don't expect it to change seeing that it's a common base for their Win32+dotNET products;</p> <p>#5 I couldn't get a single DEXPLORER instance to stay in memory. Maybe the conditions that cause that are rather peculiar, but in all the open/closes I did, not once did I see it left or even another instance being loaded while another one was already in memory.</p> <p>#6 I had to try REALLY hard to find a component that would not get me to that component's reference help. Almost every single component, from those in a form, to even those in the component selector, got me to the proper page after pressing F1 with no further questions asked. </p> <h3>Conclusions</h3> <p>1) <strong>Definitely a much welcome improvement, but still needs a lot of work.</strong> It's sad that 9 months after the initial release that touted "Improved Help" as one of the key factors for purchasing the new version, it still fails to live to that promise. Maybe by the time they get to Delphi 2008 the help is then at the standards they said it was back on release of Delphi 2007. Let's just hope they keep improving it, because it certainly looks as they still have a lot of work to do, but as long as they keep doing it, maybe in the future we will get a decent help!</p> <p>2) There are still quite a few "place-holders" like the one in this example:<br><a href="http://lh5.google.com/Fotos.Madrugas/R08koNVd-rI/AAAAAAAAAQc/1HsE4d8DpPo/Place%20Holder%5B6%5D"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="484" alt="Place Holder" src="http://lh6.google.com/Fotos.Madrugas/R08kpdVd-sI/AAAAAAAAAQk/37lC_WLyKHA/Place%20Holder_thumb%5B4%5D" width="634" border="0"></a> </p> <p>3) I was, towards the end of my tests, prompted with this:<br><a href="http://lh3.google.com/Fotos.Madrugas/R08kqtVd-tI/AAAAAAAAAQs/WVwzK6gy3WI/Local%20Help%5B5%5D"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="484" alt="Local Help" src="http://lh4.google.com/Fotos.Madrugas/R08kr9Vd-uI/AAAAAAAAAQ0/hvqnPgVAF-8/Local%20Help_thumb%5B3%5D" width="554" border="0"></a> </p> <p>I opted to use Local Help as the primary source and haven't tested with the default option given as shown above. Seemed to work pretty much the same but only did a few more tests.</p> Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com2tag:blogger.com,1999:blog-9040327036497268290.post-67353913134705565992007-11-29T16:50:00.001+00:002007-11-29T16:55:41.979+00:00Delphi 2007 for Win32 SP3<p>This week I've been a bit sick. Nothing serious, just a nasty cold with the nasty side effect of going through paper tissues like there was no tomorrow.</p> <p>So, rather than trying really hard to stay focused on debugging tasks at hand when I had to interrupt every 30 seconds to wipe my nose, I decided it was about time to do something I've been wanting to do for a long time and just couldn't afford the time to do it: upgrade my Delphi 2007 SP1 with both the SP3 and the improved help files that were released after that. That's something that doesn't require much concentration and is "compatible" with using paper tissues every 30 seconds...</p> <p>So, I start by going to the Delphi registered user's downloads and download two files:</p> <ul> <li><a href="http://cc.codegear.com/item/25015">Delphi 2007 for Win32 R2/Update 3 ISO</a> (4.16 GB, updated 2007/09/14) <li><a href="http://cc.codegear.com/item/25163">CodeGear RAD Studio 2007 Help Update 1</a> (473 MB, updated 2007/11/15)</li></ul> <p>Armed with those files, I reset my computer to a ghost file with nothing but Windows XP SP2 + patches + drivers. After a few hours of installing more patches and all the software I use *except* Delphi (a process that is now much faster as I keep many utilities pre-installed on my D:\Utils folder), it was time to tackle the main procedure: Install Delphi 2007 SP3.</p> <p>So, I start by creating a new ghost image to have a more recent "fall-back" should something fail, and I mount the ISO on a Virtual CloneDrive.</p> <p>My first impression is not good when I double-click the drive:</p> <p><a href="http://lh6.google.com/Fotos.Madrugas/R07tvtVd-bI/AAAAAAAAAOc/HrsAxocP3tg/Error012"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="93" alt="Error01" src="http://lh3.google.com/Fotos.Madrugas/R07tw9Vd-cI/AAAAAAAAAOk/jP6StUZsalc/Error01_thumb" width="204" border="0"></a> <a href="http://lh3.google.com/Fotos.Madrugas/R07tx9Vd-dI/AAAAAAAAAOs/XtuQFU9J7tA/Error022"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="149" alt="Error02" src="http://lh6.google.com/Fotos.Madrugas/R07tytVd-eI/AAAAAAAAAO0/P0UuPYZizOA/Error02_thumb" width="204" border="0"></a> <a href="http://lh6.google.com/Fotos.Madrugas/R07tztVd-fI/AAAAAAAAAO8/7PJOBjecPVA/Error032"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="149" alt="Error03" src="http://lh6.google.com/Fotos.Madrugas/R07t0tVd-gI/AAAAAAAAAPE/WPPDkEfEY18/Error03_thumb" width="204" border="0"></a> </p> <p>I then proceed to open the drive instead and manually click the install file which brings me to this:</p> <p><a href="http://lh4.google.com/Fotos.Madrugas/R07t2NVd-hI/AAAAAAAAAPM/XSLDrxVYQrk/InstallLauncher2"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="151" alt="InstallLauncher" src="http://lh3.google.com/Fotos.Madrugas/R07t29Vd-iI/AAAAAAAAAPU/dNx-dhrBwpE/InstallLauncher_thumb" width="204" border="0"></a> </p> <h3>Pre-Reqs</h3> <p><a href="http://lh3.google.com/Fotos.Madrugas/R07t39Vd-jI/AAAAAAAAAPc/S8iDQwKjj0k/PreReqsDiskSpace7"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="204" alt="Pre-Reqs Disk Space" src="http://lh6.google.com/Fotos.Madrugas/R07t4tVd-kI/AAAAAAAAAPk/oZql98TDyMA/PreReqsDiskSpace_thumb3" width="177" align="left" border="0"></a> From this point on, everything runs much smoother: I proceed to install the pre-reqs, which I intentionally had not installed before, and then a reboot is in order.</p> <p>The pre-reqs took an astonishing 2 GB of my C: drive as you can see from the image on the left. After closer scrutiny, you can easily see that it still suffers from the same "bugs" as the original install, namely, caching the same install files in several different places. That's 1.1 GB worth of .NET SDK install files in those two folders marked in the image.</p> <p>This whole process did complete without any problems and within approximately 10 minutes, after which I had to reboot to proceed with the install.</p> <p> </p> <p> </p> <h3>Install</h3> <p><a href="http://lh5.google.com/Fotos.Madrugas/R07t5dVd-lI/AAAAAAAAAPs/7pdO4FUUIpc/DelphiDiskSpace3"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="204" alt="Delphi Disk Space" src="http://lh4.google.com/Fotos.Madrugas/R07t6NVd-mI/AAAAAAAAAP0/LKJ6Kd-tuLA/DelphiDiskSpace_thumb1" width="136" align="left" border="0"></a> Then, on to installing Delphi 2007 for Win32 SP3. After inputting my registration data, I selected to install everything available to my PRO SKU, including Rave Reports. The whole process took around 15 minutes and again proceeded with no problems.</p> <p>As you can see, Delphi itself, discounting the pre-reqs, requires around 1.5 GB in the Professional Win32 SKU. That's roughly 450 MB for cached install files, 340 MB for help files and 690 MB for CodeGear files in either the program folder or common files.</p> <p>I could have ran the IDE, but instead I opted for installing the Help Update. The one minor quirk about it, is that you need to go to a command line and type HelpSetup /upgrade. But the upgrade ran smoothly and this time I didn't time it, but it was around 10 or 15 minutes. Not worth another space screenshot as it only differed in a couple MB.</p> <p> </p> <h3>Full space report</h3> <p><a href="http://lh4.google.com/Fotos.Madrugas/R07t7NVd-nI/AAAAAAAAAP8/RMkwdjx2r5U/FullDiskSpace3"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="204" alt="Full Disk Space" src="http://lh3.google.com/Fotos.Madrugas/R07t79Vd-oI/AAAAAAAAAQE/l11GT0tSWu8/FullDiskSpace_thumb1" width="135" align="left" border="0"></a> To the left you can find a FULL disk space report before installing even the pre-reqs and after installing Delphi and the help update. As you can see, that's 3.7 GB worth of stuff, from pre-reqs to cached files to more cached files to the proper program files. Not really an improvement over the original setup, IIRC... However, since I believed that at least 1.1 GB of this can be safely shaved, that's what I'll did next. So, I removed the first of the two folders marked in the Pre-Reqs image above and was surprised to find out that the 2nd one was no longer there. However, the total space used was not consistent with that 2nd folder being removed, so after a quick search, I found out that it had been instead moved into my own Local Settings rather than the All Users' one. That's consistent with the choice I was given of installing for myself only (which I chose), or installing for all users. So, I deleted that 2nd folder and then ran Windows Update to download the latest .NET 2 security updates. As expected, it worked flawlessly, and I don't expect to be running into problems by not having those files around. Of course, Windows Update doesn't update the SDK itself, so this was not a big test. But if you want to play safe, just burn those two folders to a DVD should they be required at some upgrade point in the future...</p> <p>So, the (current) final space used is down to 2.5 GB, but that's without having yet followed my own guide on how to trim some more MBs out of it. <em><strong>That's intentional,</strong> as I want to test the help file and see if it has been REALLY improved without using my own tweaks.</em> That will be the subject of <strong>my next post</strong> which should be posted either later today or tomorrow, if all goes as planned.</p> <h3>Conclusion</h3> <p>The whole process ran very smoothly, even if CodeGear still thinks that, just because disk space is cheap, they can waste as much as they want. Sure, disk space IS cheap, but if you want to create a ghost image of your main working drive and burn that to a DVD, having 2 GB worth of data or having 2 GB worth of data + 2 GB of worthless cached files DOES make a big difference in making it all fit onto a DVD or not. The way I do it, if anything other than an hardware failure goes very wrong, I can be up and running with a working configuration by popping a DVD into my drive and restoring my system to a full working condition in under 20 minutes, instead of re-installing everything for the better part of 1 or 2 days. The same problem applies to creating and backing up a Virtual Machine with a full working install, so, <strong><em>please CodeGear, stop wasting one's disk space just because it's "apparently" cheap!</em></strong></p> Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com3tag:blogger.com,1999:blog-9040327036497268290.post-32746996308408661372007-09-24T09:21:00.001+00:002007-09-24T09:21:17.296+00:00Windows Live Writer and Pascal Code Formatting (updated)<p>Since Steve Dunn has updated his WLW add-in, I checked it and found out that it still doesn't use the fixed pascal definition file that I sent Actipro some months ago.</p> <p>So, if you want proper pascal syntax highlighting, download <a href="http://dunnhq.com/codeformatterforwindowslivewriter">his control</a>, follow his instructions and afterwards copy <a href="http://fmadsoft.com/mmd/files/ActiproSoftware.Pascal.xml">this file</a> over the same named one in the languages folder.</p> <p>Among other fixes that I recall are some missing keywords (unit for instance) and support for // comments and proper nested comment / string support.</p> Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com3tag:blogger.com,1999:blog-9040327036497268290.post-54305894054385956802007-07-27T12:04:00.001+00:002007-07-27T13:45:50.553+00:00The best 330 MB of my C: drive...<p>Well, I hate to be negative about stuff, I really do, but I just can't help it. Having fought so many times with a lacking help system, I finally decided it was time to uninstall it. It's pretty useless to me as if I want MS docs I'll search for them on the net and they will be more up to date. So, I finally decided to go to Add-Remove Programs and Change the Rad Studio installation to remove those help files.</p> <p>In doing so, I found out a few more things:</p> <ol> <li>Install-aware sucks even more than I thought! What used to be a few seconds on a decent installer takes over 6 minutes to do in this Install-Aware setup! <li>They use a lot of progress bars but really show no progress: a blinking light would show the same information... At one point 2 were present at once and really I could be no closer or farther away from knowing how much more time I'd have to wait as they were file-based progress bars and not *process* based ones... <li>What the heck is a "Cach"? As in "Removing Cach folder xxx" <li>Shouldn't I get a more graceful message when pressing F1 on RAD Studio if I chose to remove the help files? (in a legitimate way and not hacking the files!)<br>And the message even shows in Portuguese even though my Windows and RAD Studio are both English...<br><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="155" alt="X" src="http://fmadsoft.com/mmd/images/Thebest330MBofmyCdrive_A6B4/X.png" width="400" border="0"> <li>Finally, if I chose to remove the cached install files, what are 100 MB left there for?</li></ol> <p>This is all a nasty combo of a lousy installer with probably some lousy install scripts...</p> <p>Q: Would I uninstall Delphi 2007?</p> <p>A: Well, I've got used to it and it works well overall so most likely no, I'll keep using it. I just got fed up with the so labeled "Improved Help"... Pitty that MSFT set the road that others followed by releasing unfinished software...</p> <p>For those who may not like me "bitching" about this: would you like to buy a car that "sort of works"? And that has to go through a few Service Packs before you really got what you're promised it would be before purchasing? I'm just applying the same principle to Software...</p> <p>[EDIT: I've just "fixed" that error message: removed the htmlhelp2100.bpl (or something like that) from the known IDE packages so now pressing F1 silently fails. I'll probably try and find some replacement help files/reader as I vaguely remember something about using previous versions help files. Then I'll try downloading those help files from the customer area if it works! :)]</p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com8tag:blogger.com,1999:blog-9040327036497268290.post-7818268475575013922007-07-16T11:40:00.001+00:002007-07-16T11:51:01.331+00:00No comments...<p>Well, I lied! I have one comment: I did press the feedback link, even though the question looks almost a joke! :)</p> <p><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="408" alt="Joke" src="http://fmadsoft.com/mmd/images/Nocomments_B24B/Joke.png" width="532" border="0"> </p> <p>BTW: The Void stamp and yellow highlighting is just me playing around with <a href="http://www.techsmith.com/screen-capture.asp">SnagIt</a>! :)</p> <p><strong>EDIT: It appears it gets even better:</strong></p> <p><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="3829" alt="Bug2" src="http://fmadsoft.com/mmd/images/Nocomments_B24B/Bug2.png" width="826" border="0"></p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com8tag:blogger.com,1999:blog-9040327036497268290.post-74114007452544837492007-07-14T14:32:00.001+00:002007-07-14T14:48:02.975+00:00Delphi "killed" by VB6? WTF?<p>Well, I read in <a href="http://www.dummzeuch.de/news2007/english.html#a2007-07-14">TWM's blog</a> that Delphi is listed in the <a href="http://www.softwaredeveloper.com/features/ghosts-in-machine-071207/">12 languages that never took off</a>.</p> <p>Since I can't comment on either page, I decided to comment in my blog...</p> <p>I can only say one thing: that article reminds one of the languages mentioned in it (the one that starts with brain...); that article is surely someone's brain fart!</p> <p>Saying that VB6 killed Delphi and showing a stupid piece of partial code as if it's a "hello world" program???</p> <p>And for those that would accuse me of attacking that article because I'm a Delphi fan-boy: just read my blogs here and you'll know that I'm everything <strong><em>but</em></strong> a fan-boy!</p> <p>But I also don't like to see some moron (sorry, but can't help to use that word), say such things about Delphi.</p> <p>Is that guy getting paid from MSFT or something? Or is he just a dumb arse?</p> <p><strong>[Edit:]</strong></p> <p>I've since gone to digg.com and checked out who <a href="http://www.digg.com/programming/Ghosts_in_the_Machine_12_Coding_Languages_That_Never_Took_Off/who">blogged about that</a> digg among other things: it turns out that my impression that digg was just full of meaningless trash is correct! Of those that "blogged" about that digg, nearly all are non-related commercial sites of some sort that are probably just using some robot-like technology to crank up their site in the listings!</p> <p>Now, I already <strong><em>thought</em></strong> that digg was a waste of time but now I know for sure that <strong><em>it is</em></strong> really a waste of time! At least that dumb article had some usefulness! :)</p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com8tag:blogger.com,1999:blog-9040327036497268290.post-1173096293001367362007-07-13T15:49:00.001+00:002007-07-13T15:49:43.329+00:00Command line: do you still use it?<p>Well, I do and for quite some years I've been using JPSoft's 4NT. I have some nice batch files, custom prompts, custom functions and it has a whole lot of built-in commands, variables and functions as well.</p> <p>But, not only do I find myself doing less actual command line stuff, I sometimes get a bit mad at this product, like yesterday when I was attempting to use drive aliases inside a function and later found out that it doesn't work there, only in commands... Kind of the legacy from a program that, the author has admitted, has a ton of different parsers for a ton of different functions/commands. It's also partly due to the fact of maintaining compatibility with command.com and cmd.exe in their many versions and changes so far, but sometimes I think that it would be better to use something else for my command line scripting, perhaps something that doesn't carry this legacy compat baggage and thus can have a more uniform and <em>predictable</em> syntax.</p> <p>Which brings me to the question: do you still do comand line? What tools/programs do you use for it? Or do you rely on good old fashioned cmd.exe for your command line work?</p> <p>I've once tried to use PowerShell from MSFT, but, not only did it still have a lot of rough edges (like, for instance, not being able to easily work on files with some valid dos file name characters!), and, even though it is a very considerable change from cmd.exe, and sure looks powerful, it wasn't that much better than cmd.exe and even a bit lacking in many basic functions, at least a couple years ago when I tested it!</p> <p>So, if you have a nice experience with something other than 4NT/CMD/COMMAND, let me know what you use and how happy you're about it and I may even go and try that for a change!</p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com11tag:blogger.com,1999:blog-9040327036497268290.post-63384240961525767532007-07-10T15:55:00.001+00:002007-07-10T16:05:58.038+00:00Quick tip for compiling/testing DLLs<p>Now that Delphi 2007 is using MSBuild, you can take advantage of the Pre-Build events to automate a common headache: killing that task that is using your DLL before you build it!</p> <p>I'm currently developing an Outlook add-in so I found myself repeatedly quitting Outlook or getting an error because Delphi can't generate the DLL if I don't close Outlook, so, to solve that, and since, for some weird reason, I got used to always build instead of compiling, I just added the following command to this project's Pre-Build Events:</p> <blockquote> <p>taskkill /F /IM outlook.exe</p> <p>DIR >NUL</p></blockquote> <p>And that's all there is to it. You can also launch outlook after the build so as to immediately test your changes by adding the proper command to the Post-Build events, but I didn't add that as sometimes I do a few builds just to check syntax/compiler errors while I'm still working on something and I don't want to have outlook popup everytime...</p> <p>Also, you can try without /F (force) and if your outlook or dll host can terminate gracefully in a speedy way you won't need to force termination, but in my PC and with Outlook it doesn't quit that fast, so I need the /F...</p> <p>EDIT: The DIR >NUL command is just so that, should you not currently have outlook running, the error from taskkill won't stop your build process! :)</p> <p><em>BTW: you can achieve something similar in BDS 2006 (and maybe 2005: haven't tested on this one), if you read my blog post about <a href="http://memyselfanddelphi.blogspot.com/2007/03/pre-and-post-build-automation-in-delphi.html">adding pre/post build events to BDS 2006</a>...</em></p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com5tag:blogger.com,1999:blog-9040327036497268290.post-63896422203986060622007-07-06T14:53:00.001+00:002007-07-06T16:22:03.654+00:00Code formatting and readability<p>Well, each developer tends to have his own set of rules be that for code formatting, identifier naming or whatever. And each developer, when looking at someone else's code tends to go like: "wow: what was this guy thinking?"...</p> <p>Here's a piece of auto-generated code from Add-In Express:</p> <p></p> <div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:63af1a4d-3e90-4c84-b3d0-410644eb1e4a" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;;overflow: auto;"><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> ActivateEvent(Sender: TObject);<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> ClickEvent(Sender: TObject);<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> CreateEvent(Sender: TObject);<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> DblClickEvent(Sender: TObject);<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> DeactivateEvent(Sender: TObject);<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> DestroyEvent(Sender: TObject);<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> KeyPressEvent(Sender: TObject; </span><span style="color: #0000FF; ">var</span><span style="color: #000000; "> Key: Char);<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> PaintEvent(Sender: TObject);<br /></span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div><br /><p></p><br /><p>I find this very annoying and hard to read/browse! So, even though I know it serves no useful purpose other than please my eyesight, I turn that into something like this:</p><br /><p></p><br /><div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:dff11ecd-689f-4ec7-97ca-70d58b15640d" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;;overflow: auto;"><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> ActivateEvent ( Sender: TObject );<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> ClickEvent ( Sender: TObject );<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> CreateEvent ( Sender: TObject );<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> DblClickEvent ( Sender: TObject );<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> DeactivateEvent( Sender: TObject );<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> DestroyEvent ( Sender: TObject );<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> KeyPressEvent ( Sender: TObject; </span><span style="color: #0000FF; ">var</span><span style="color: #000000; "> Key: Char);<br /> </span><span style="color: #0000FF; ">procedure</span><span style="color: #000000; "> PaintEvent ( Sender: TObject );<br /></span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div><br /><p></p><br /><p>Now, isn't this 2nd version much easier on the eyes? Surely it compiles the same as the 1st one no faster nor slower no more and no less bytes used, but for us, humans, it's way easier to look at!</p><br /><p>Heck, I even do this on forms after they are stable enough and I know I won't be adding too much stuff/events to it! :) And if I do add, I'll re-sort and re-format those lines! :)</p><br /><p>There are a ton more of things I change for cosmetic reasons, such as placing <strong>begin</strong>/<strong>end</strong> on pretty much every single <strong>if</strong>, even if it really wasn't needed (there are exceptions mainly when the one-liner if's are used as a sort of case construct where keeping them one-lined does help readability).</p><br /><p>Again, a small sample:</p><br /><p></p><br /><div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:0d717475-6134-4181-88ba-f641f8903a10" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;;overflow: auto;"><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> FPropertyPageSite </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">nil</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "><br /> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> Assigned(ActiveFormControl) </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "><br /> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> Assigned(ActiveFormControl.ClientSite) </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "><br /> ActiveFormControl.ClientSite.QueryInterface( IID_PropertyPageSite, FPropertyPageSite );<br /></span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div><br /><p></p><br /><p>And, after reformatting:</p><br /><p></p><br /><div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:cbcee4af-8c7c-431a-9801-08e85b1f6450" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;;overflow: auto;"><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> FPropertyPageSite </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">nil</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">begin</span><span style="color: #000000; "><br /> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> Assigned(ActiveFormControl) </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">begin</span><span style="color: #000000; "><br /> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> Assigned(ActiveFormControl.ClientSite) </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">begin</span><span style="color: #000000; "><br /> ActiveFormControl.ClientSite.QueryInterface( IID_PropertyPageSite, FPropertyPageSite );<br /> </span><span style="color: #0000FF; ">end</span><span style="color: #000000; ">;<br /> </span><span style="color: #0000FF; ">end</span><span style="color: #000000; ">;<br /> </span><span style="color: #0000FF; ">end</span><span style="color: #000000; ">;<br /></span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div><br /><p></p><br /><p>Now, you may think that there is not much difference in here, but there is! Especially if some have <strong>begin</strong>/<strong>end</strong> and others don't and depending on what code follows. Plus, always using <strong>begin</strong>/<strong>end</strong> means you don't need to look too hard on the code as to where to place the <strong>begin</strong>/<strong>end</strong> pair when instead of a single line inside a multiple <strong>if</strong> you need to have two lines of code: all the code layout is perfectly done and you just add that extra line where you want it without much trouble...</p><br /><p>There are many more things that I change, even in code that is not my own as long as I'm the only one using it and as long as I need to change/edit/maintain it, but I thought of these as I was making some changes to this code and figured I'd take a few mins break and blog about it! :)</p><br /><p>Also, you can take advantage of Delphi's built-in begin/end helper: just type <strong>begin</strong> at the end of a line, place your cursor to the end of the last line of the code block to be enclosed and press <strong>enter</strong>: <em>et voilá</em>, instant <strong>end</strong> properly lined up, courtesy of Dephi's IDE... :)</p><br /><p><strong><em>[EDIT: I knew I was being lazy with the begin/end/if example so here's a better one...]</em></strong></p><br /><p></p><br /><div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:20604149-5508-4a8c-a605-8ca64aed076e" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;;overflow: auto;"><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; "> Messy version</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">begin</span><span style="color: #000000; "><br /> Result :</span><span style="color: #000000; ">=</span><span style="color: #000000; "> (AControl.Handle </span><span style="color: #000000; ">=</span><span style="color: #000000; "> Focused);<br /> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">not</span><span style="color: #000000; "> Result </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "><br /> </span><span style="color: #0000FF; ">for</span><span style="color: #000000; "> i :</span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #800080; ">0</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">to</span><span style="color: #000000; "> AControl.ControlCount </span><span style="color: #000000; ">-</span><span style="color: #000000; "> </span><span style="color: #800080; ">1</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">do</span><span style="color: #000000; "><br /> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> AControl.Controls[i] </span><span style="color: #0000FF; ">is</span><span style="color: #000000; "> TWinControl </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "><br /> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> TWinControl(AControl.Controls[i]).Handle </span><span style="color: #000000; ">=</span><span style="color: #000000; "> Focused </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "><br /> Result :</span><span style="color: #000000; ">=</span><span style="color: #000000; "> True;<br /> </span><span style="color: #0000FF; ">else</span><span style="color: #000000; "><br /> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> TWinControl(AControl.Controls[i]).ControlCount </span><span style="color: #000000; ">></span><span style="color: #000000; "> </span><span style="color: #800080; ">0</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "><br /> Result :</span><span style="color: #000000; ">=</span><span style="color: #000000; "> SearchForHWND(TWinControl(AControl.Controls[i]), Focused);<br /></span><span style="color: #0000FF; ">end</span><span style="color: #000000; ">;<br /><br /></span><span style="color: #008000; ">//</span><span style="color: #008000; "> Cleaned up version</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">begin</span><span style="color: #000000; "><br /> Result :</span><span style="color: #000000; ">=</span><span style="color: #000000; "> (AControl.Handle </span><span style="color: #000000; ">=</span><span style="color: #000000; "> Focused);<br /> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">not</span><span style="color: #000000; "> Result </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">begin</span><span style="color: #000000; "><br /> </span><span style="color: #0000FF; ">for</span><span style="color: #000000; "> i :</span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #800080; ">0</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">to</span><span style="color: #000000; "> AControl.ControlCount </span><span style="color: #000000; ">-</span><span style="color: #000000; "> </span><span style="color: #800080; ">1</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">do</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">begin</span><span style="color: #000000; "><br /> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> AControl.Controls[i] </span><span style="color: #0000FF; ">is</span><span style="color: #000000; "> TWinControl </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">begin</span><span style="color: #000000; "><br /> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> TWinControl(AControl.Controls[i]).Handle </span><span style="color: #000000; ">=</span><span style="color: #000000; "> Focused </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">begin</span><span style="color: #000000; "><br /> Result :</span><span style="color: #000000; ">=</span><span style="color: #000000; "> True;<br /> </span><span style="color: #0000FF; ">end</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">else</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">begin</span><span style="color: #000000; "><br /> </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> TWinControl(AControl.Controls[i]).ControlCount </span><span style="color: #000000; ">></span><span style="color: #000000; "> </span><span style="color: #800080; ">0</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">then</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">begin</span><span style="color: #000000; "><br /> Result :</span><span style="color: #000000; ">=</span><span style="color: #000000; "> SearchForHWND(TWinControl(AControl.Controls[i]), Focused);<br /> </span><span style="color: #0000FF; ">end</span><span style="color: #000000; ">;<br /> </span><span style="color: #0000FF; ">end</span><span style="color: #000000; ">;<br /> </span><span style="color: #0000FF; ">end</span><span style="color: #000000; ">;<br /> </span><span style="color: #0000FF; ">end</span><span style="color: #000000; ">;<br /> </span><span style="color: #0000FF; ">end</span><span style="color: #000000; ">;<br /></span><span style="color: #0000FF; ">end</span><span style="color: #000000; ">;</span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div><br /><p></p><br /><p>Of the two pieces of identical code, which one do you think is easier to add something to? Say an else to one of the if's or some other instruction in any of the "branches"... And note that, the indentation on the messy one is not that messy and it helps a bit, but you sure can follow the cleaned up version better when trying to see all possible outcomes from that function, no? It certainly works <strong>much</strong> better for me at least! :)</p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com16tag:blogger.com,1999:blog-9040327036497268290.post-59144516961681232312007-07-06T11:34:00.001+00:002007-07-06T11:35:06.978+00:00Bugsie - Part 2<p>In my <a href="http://memyselfanddelphi.blogspot.com/2007/07/can-you-confirm-this-bug.html">previous post</a>, I mentioned a minor layout bug that I watched during the CodeRage Encore presentations. I can now consistently replicate it but other people have mixed success depending on what system they use. Here are the necessary steps to reproduce that show that it is in fact a question of the IDE not redrawing the gray/black corner handles.</p> <ol> <li>File -> New Form</li> <li>Add 2 buttons to the form such that they're not aligned</li> <li>Drag a selection rectangle and note which button has darker corner handles</li> <li>Right-Click the <strong>other</strong> button, that is, the one with the lighter corners</li> <li>Select Position -> Align -> Cancel</li> <li>At this point, if the bug happens on your system, the corner grabbing rectangles should not have changed colors, i.e., the button with the darker corners is still the same</li> <li>If step 6 happens on your system, then click the Align Tops on the Align toolbar and see that the anchor button was the <strong>wrong</strong> button!</li></ol> <p>Now, I said that you could see that it was a display issue. Here's how to do that:</p> <ol> <li>Repeat steps 1-5 on the above list</li> <li>If, after step 5, you can confirm that the button corner handles haven't changed color, i.e., bug is happening, then simply open up something that will cover the form so as to force Delphi to later redraw it (Internet Explorer, FireFox, Explorer, Outlook, etc)</li> <li>When you move that window away (or switch back to Delphi), you will see that the darker corners are now properly displayed.</li></ol> <p>Here's the QC report created on this one:</p> <p>Report No: 48631 Status: Reported<br>Form designer may fail to correctly update changed anchors<br><a href="http://qc.codegear.com/wc/qcmain.aspx?d=48631">http://qc.codegear.com/wc/qcmain.aspx?d=48631</a> <p>BTW, if you need more information on the black/gray corner handles, check <a href="http://www.stevetrefethen.com/blog/AligningSizingAndSpacingCommandsInTheDelphi2007VCLDesigner.aspx">this post</a> from Steve Trefethen...</p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com2tag:blogger.com,1999:blog-9040327036497268290.post-49471822864597121522007-07-05T17:18:00.001+00:002007-07-05T23:13:57.235+00:00Can you confirm this bug?<p>Well, 3 months ago, when watching one of the CodeRage Encore presentations, I witnessed a bug in action (more on that sooner!); even though I tried (as you can see in the replay), I couldn't get the presenter to replicate the bug. Now that the replays are finally available and now that I know how to skip so as to quickly find out which presentation and at what point it was (3 months make you forget a lot of stuff, especially when you were thinking the replays would be on after a week or so!), I've finally confirmed that I <strong>did</strong> indeed saw a bug.</p> <p>Can you please go <a href="http://video.codegear.com/CodeRage2007EncoreArchives/CodeRageEncoreCompilerRTLWeb/CodeRageEncoreCompilerRTLWeb.html">here</a>, wait for the video to fully stream (progress bar fully light gray) and then position a few seconds before 06:38 where the bug happens and confirm that it is indeed a bug? I'll report it in QC as soon as I get some 3rd party confirmation on that.</p> <p>Here's the bug: if you notice in that presentation, there are 3 buttons selected; the middle button has darker corners meaning that it's the button that is used to "control" the action, that is, whatever you choose it relates to <strong>that</strong> button. Notice that, when selecting the "Align top" the 3 buttons are (<em>incorrectly</em>!) aligned to the first button's top and <strong>not</strong> to the one with the darker corners. <strike>(Watch the video from the start for the explanation on the dark corners).</strike> <em>[Edit: the dark corners are either explained elsewhere or later in the video, not before!]</em></p> <p>If you can confirm what I saw, then please leave a comment here.</p> <p>(CodeGear should probably hire me for finding bugs for them, but since I do it for free anyway, I don't think they want to! :))</p> <p><strong><em>[EDIT:]</em></strong></p> <p>Actually, at first, after making this blog post, I thought it could be some Camtasia bug as I could not reproduce it (as I right-clicked the top-left button it was selected); I have however been able to replicate it afterwards! <p>Here are the full steps: <p>1) File->New Form<br>2) Double click 3 times on TButton<br>3) Grab button 3 to top left<br>4) Grab button 2 to mid right<br>5) Drag a selection box from upper-left to lower-right <p>At this point, Button 1 is selected; <p>6) Right-click Button 3<br>7) Choose Position->Align from the menu and Cancel <p>At this point, Button 1 still appears to be selected. <p>8) Click on Align Tops in the Align toolbar and get the wrong behavior doing the align with Button 3 instead. <p>It appears that Button 3 was in fact selected by right-clicking and that the designer didn't redraw to show that. <p>BTW: Using Delphi 2007 SP1 on Windows XP with theming active.</p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com7tag:blogger.com,1999:blog-9040327036497268290.post-73538909941597758912007-07-05T16:29:00.001+00:002007-07-05T16:29:47.348+00:00CodeGear Replays: not entirely their fault... :)<p>Well, after my <a href="http://memyselfanddelphi.blogspot.com/2007/06/codegear-encore-non-replays.html">previous</a> post, and after some comment left in by a reader, I decided to "bug" Anders (not knowing he's on vacation!), and it appears that the problem with the video not skipping to where you try to skip is Camtasia's fault... Having tried Camtasia in the past, and seeing how many "helper" files it generates and all of them including the video duration, I would expect it to be able to do something as simple as positioning the video cursor somewhere where the video has already streamed (you can tell by the bar color, gradually filling with a lighter gray where it has already streamed).</p> <p>It appears that instead, you <strong>have</strong> to wait until the <strong>whole</strong> video has finished streaming before you can reliably position the video playback cursor somewhere! I just browsed some of <a href="http://video.techsmith.com/snagit/latest/edu/tutorials/enu/sng_tutorials.html">their own videos</a> and noticed that they too suffer from the same problem so it does not look like it's CodeGear to blame on this one! :)</p> <p>On the plus side, <u><em>Anders also said he might be looking at making the download links available</em></u> after returning from his vacation next week...</p> <p>For now, you can start the playback of any video, pause it (if you don't want to be listening to it while it streams), and when the progress bar has completely filled light gray, you can then position the playback cursor wherever you want and use that as a quick way to skip past content that you want to, well, skip! :)</p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com0tag:blogger.com,1999:blog-9040327036497268290.post-26071929044995664462007-06-28T23:43:00.001+00:002007-06-28T23:43:22.814+00:00CodeGear Encore - The (non) Replays<p>As you may have noticed, CodeGear finally placed the <a href="http://dn.codegear.com/article/36688">replays</a> online. Well, I'm not even going to mention that the initial plan was to have those available only to registered Delphi Customers as it was in those terms that the event took place... (Well, it seems I <strong>did</strong> mention it, but I have no problem that it's available for everyone!)</p> <p>What I'm complaining here is about the <strong><em>lousy job</em></strong> done that took them <strong><em>3 whole months</em></strong> to do!</p> <p>Sure, I know that CodeGear has been busy but did they really need 3 whole months between the CodeRage Encore event and this (let's be nice) publishing of the sessions?</p> <p>I mean: where are the download links? Only choice is to view online. But much worst than that, try and position the video replay cursor somewhere in the timeline: it will never be where you put it, thus completely preventing you from skimming those contents...</p> <p>Three months ago, when the event took place, I saw what looked like a bug; I tried to get the presenter to repeat the steps but that didn't seem to reproduce the bug; since we had already been promised the replays before the event started, I didn't worry too much. I though: I'll wait for the replays and try and see if I did really see a bug in action and if true, I'll report it, if not, no further action will be needed. </p> <p>Well, never in a million lifetimes would I think that publishing those replays would take 3 whole months and, worst, that after those 90 days, the job would still be done in a very amateurishly way...</p> <p><em><u>CodeGear, this is <strong>not</strong> the way to tell us customers that one of your goals is quality: doing a bad service and taking so long to do it so bad is <strong>not</strong> what I or many others would call <strong>quality</strong>...</u></em></p> <p>BTW: Should the responsible at CG want to at least fix the skimming bit, it has to do with the many files that Camtasia uses and the different ways of indicating the video size: you <strong><em>can't</em></strong> re-use them for other presentations <em><strong>unless</strong></em> they have the exact same duration, otherwise you'll end up in the mess you have managed to do...</p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com3tag:blogger.com,1999:blog-9040327036497268290.post-44346119072668946602007-06-20T11:13:00.001+00:002007-09-24T09:25:08.993+00:00Windows Live Writer, Spell Checker, Pascal Code Formatting<p><em><strong><font color="#ff0000">September 2007 edit: Steve Dunn has updated his control, and so this no longer applies. Check my </font><a href="http://memyselfanddelphi.blogspot.com/2007/09/windows-live-writer-and-pascal-code.html"><font color="#ff0000">other post</font></a><font color="#ff0000"> about using his newer version and "fixing" the used Pascal definition file.</font></strong></em></p> <p>After reading <a href="http://17slon.com/blogs/gabr/2007/06/spell-checking-in-windows-live-writer.html">this post</a> from Primoz Gabrijelcic, which took me to <a href="http://jtbworld.blogspot.com/2007/06/windows-live-writer-spell-checking.html">this other post</a> from Jimmy Bergmark, my Windows Live Writer has once again the Spell check option.</p> <p>In the 2nd post mentioned above, I saw a reference to another plug-in, a code-formatting plug-in, something that I wanted to add to WLW too, so I decided to check it out. I downloaded it (<a href="http://dunnhq.com/codeformatterforwindowslivewriter">from here</a>), and was a bit surprised about the lack of Pascal as a choice for language. A quick check later and I saw the different languages each had an XML file, so I thought for myself: "It can't be that hard to grab one and modify it for Pascal". And so, I started the conversion process. Unfortunately, I had placed too much faith on the recently fixed "Improved Help" of Delphi 2007: needless to say that, after a few minutes of fighting with the help, which, although improved since Delphi 2007's release as at least now it no longer renders the IDE unusable if you press F1 on a menu, I had nevertheless to give up. Finding basic things in that help is a pain in the ***, and that's putting it nicely! Be that using filters or no filters, language filters or no language filters, finding Pascal help for a list of basic types has proven to be a much greater challenge than it should have been.</p> <p>So, attempt number two: Google to the rescue! I googled a bit and within seconds had found <a href="http://www.actiprosoftware.com/Download/Freeware.aspx?ProductGroupKey=CH">this other page</a>, from where I could download the controls that were used by this code formatting plug-in, so, after typing a fake name and e-mail (I hate these "we want your name before you can download" type of sites!), I downloaded the free controls. Extracted the ActiproSoftware.Pascal.xml file and placed it in the code formatting plug-in Languages folder and fired up WLW.</p> <p>Things didn't quite work out: no Pascal available in the language choices. A little bit more digging, and I found that the DunnHQ.Wlw.CodeFormatter.dll.config file is in fact an XML file with a list of all available languages and definitions, so, after adding the following line:</p> <div class="wlWriterSmartContent" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:a237ab2c-2c27-407a-9297-d36d98636797" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;;overflow: auto;"><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF;"><</span><span style="color: #800000;">language </span><span style="color: #FF0000;">key</span><span style="color: #0000FF;">="Pascal"</span><span style="color: #FF0000;"> definitionPath</span><span style="color: #0000FF;">="./plugins/Languages/ActiproSoftware.Pascal.xml"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/></span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div><br /><p>and restarting WLW, I "Pasted Clipboard as Code", selected Pascal from the list of languages and got this as result:</p><br /><p><a href="http://fmadsoft.com/mmd/images/WindowsLiveWriterSpellCheckerPascalCodeF_8D3A/Bugger.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="112" alt="Bugger" src="http://fmadsoft.com/mmd/images/WindowsLiveWriterSpellCheckerPascalCodeF_8D3A/Bugger_thumb.png" width="240" border="0"></a> </p><br /><p>Humm... Something is amiss surely...</p><br /><p>After another quick check, I found the source: the language definition XML files used in the plug-in have LanguageDefinitionVersion="3.0", while this one downloaded from ActivePro has LanguageDefinitionVersion="4.0", so, time to go check if I can find one of those for version 3...</p><br /><p>(At this point, I can not even save a draft of this post as I get this when trying to do it:)</p><br /><p><a href="http://fmadsoft.com/mmd/images/WindowsLiveWriterSpellCheckerPascalCodeF_8D3A/Bugger2.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="112" alt="Another bugger" src="http://fmadsoft.com/mmd/images/WindowsLiveWriterSpellCheckerPascalCodeF_8D3A/Bugger2_thumb.png" width="240" border="0"></a> </p><br /><p>(D:\XDesk is my Desktop folder: somehow it's trying to load the language definition for the small line of XML above from the Desktop instead of from the program's start location..)</p><br /><p>So, after a quick copy/paste of that plugins folder to my desktop, I saved, quit WLW and resumed Googling...</p><br /><p>It turns out that the format has been significantly changed between versions 3 and 4 and that the Pascal definition was added only in version 4. Luckily, at this point I also found another code-formatting plug-in that seems to be based around v 4 as it lists Pascal in the available languages! So, after downloading and trying <a href="http://www.istaysharp.net/index.php?title=SyntaxColor4Writer">SyntaxColor4Writer</a>, I was again in a dead end: it's for Beta 1 and would not work on Beta 2!</p><br /><p>Well, I ended up clicking the "Add a Plugin..." button in WLW and downloading <a href="http://gallery.live.com/liveItemDetail.aspx?li=d4409446-af7f-42ec-aa20-78aa5bac4748&bt=9&pl=8">Code Snippet plugin for Windows Live Writer</a> so that's what I'll try next. If it doesn't work ok, I'll update this blog post asap. Another dead end... List of supported languages:</p><br /><p><a href="http://fmadsoft.com/mmd/images/WindowsLiveWriterSpellCheckerPascalCodeF_8D3A/image.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="119" alt="image" src="http://fmadsoft.com/mmd/images/WindowsLiveWriterSpellCheckerPascalCodeF_8D3A/image_thumb.png" width="78" border="0"></a> </p><br /><p>Uninstall this one, try the "Add a Plugin..." button again... Another quick look finds another one that is probably based around the same source as the list of languages is identical, so, back to Google again... (I really should be working instead!)</p><br /><p>Back to the starting idea and let's see how hard it is to retrofit v 4 Pascal definition XML into v3 controls. It turns out that it's VERY easy! All you need to do for it to start working is change both 4s in the first line of the Pascal.xml file into 3s. Like this:</p><br /><p></p><br /><div class="wlWriterSmartContent" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:8351b219-70f7-4f7a-839c-e54c742e3926" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;;overflow: auto;"><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF;"><</span><span style="color: #800000;">SyntaxLanguage </span><span style="color: #FF0000;">Key</span><span style="color: #0000FF;">="Pascal"</span><span style="color: #FF0000;"> LanguageDefinitionVersion</span><span style="color: #0000FF;">="3.0"</span><span style="color: #FF0000;"> Secure</span><span style="color: #0000FF;">="True"</span><span style="color: #FF0000;"> xmlns</span><span style="color: #0000FF;">="http://ActiproSoftware/SyntaxEditor/3.0/LanguageDefinition"</span><span style="color: #0000FF;">></span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div><br /><p></p><br /><p>So, after that it's now working with Pascal code. There are a couple things that don't look that good, namely the wrong color of keywords such as "unit", "uses" and others, but it should be easy now to fix the Pascal.xml file and simply add those keywords. So, with a little help from Delphi Basics to get what the built-in help in Delphi 2007 won't give me (a list of reserved keywords), here's how some sample Pascal code looks like:</p><br /><div class="wlWriterSmartContent" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:d693ccb8-7c10-4e56-8d31-5e8b3a116380" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;;overflow: auto;"><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF;">unit</span><span style="color: #000000;"> uHeader;<br /><br /></span><span style="color: #0000FF;">interface</span><span style="color: #000000;"><br /><br /></span><span style="color: #0000FF;">uses</span><span style="color: #000000;"><br /> Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,<br /> Outlook2000, adxolFormsManager, StdCtrls;<br /><br /></span><span style="color: #0000FF;">type</span><span style="color: #000000;"><br /> TfrmHeader </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">class</span><span style="color: #000000;">(TadxOlForm)<br /> lbxHeader: TListBox;<br /> </span><span style="color: #0000FF;">procedure</span><span style="color: #000000;"> adxOlFormADXSelectionChange(Sender: TObject);<br /> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"><br /> </span><span style="color: #008000;">{</span><span style="color: #008000;"> Private declarations </span><span style="color: #008000;">}</span><span style="color: #000000;"><br /> </span><span style="color: #0000FF;">protected</span><span style="color: #000000;"><br /> </span><span style="color: #008000;">{</span><span style="color: #008000;"> Protected declarations </span><span style="color: #008000;">}</span><span style="color: #000000;"><br /> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"><br /> </span><span style="color: #008000;">{</span><span style="color: #008000;"> Public declarations </span><span style="color: #008000;">}</span><span style="color: #000000;"><br /> </span><span style="color: #0000FF;">published</span><span style="color: #000000;"><br /> </span><span style="color: #008000;">{</span><span style="color: #008000;"> Published declarations </span><span style="color: #008000;">}</span><span style="color: #000000;"><br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /><br /></span><span style="color: #008000;">{</span><span style="color: #008000;">NOTE: The adxOlForm1 variable is intended for the exclusive use<br /> by the TadxOlFormsCollectionItem Designer.<br /> NEVER use this variable for other purposes.</span><span style="color: #008000;">}</span><span style="color: #000000;"><br /></span><span style="color: #0000FF;">var</span><span style="color: #000000;"><br /> frmHeader : TfrmHeader;<br /><br /></span><span style="color: #0000FF;">implementation</span><span style="color: #000000;"><br /><br /></span><span style="color: #008000;">{</span><span style="color: #008000;">$R *.DFM</span><span style="color: #008000;">}</span><span style="color: #000000;"><br /><br /></span><span style="color: #0000FF;">uses</span><span style="color: #000000;"> MapiDefs, MapiTags, MAPIUtil;<br /><br /></span><span style="color: #0000FF;">procedure</span><span style="color: #000000;"> StringToList( Str: string; lstResult: TStrings );<br /></span><span style="color: #008000;">//</span><span style="color: #008000;"> Convert a header string containing CR/LFs and TABs into<br /></span><span style="color: #008000;">//</span><span style="color: #008000;"> a stringlist where each new property starts on a new line</span><span style="color: #008000;"><br /></span><span style="color: #0000FF;">var</span><span style="color: #000000;"><br /> iPos : integer;<br /></span><span style="color: #0000FF;">const</span><span style="color: #000000;"><br /> CRLF </span><span style="color: #000000;">=</span><span style="color: #000000;"> #</span><span style="color: #800080;">13</span><span style="color: #000000;">#</span><span style="color: #800080;">10</span><span style="color: #000000;">;<br /></span><span style="color: #0000FF;">begin</span><span style="color: #000000;"><br /> lstResult.Clear;<br /> iPos :</span><span style="color: #000000;">=</span><span style="color: #000000;"> Pos( CRLF, Str );<br /> </span><span style="color: #0000FF;">while</span><span style="color: #000000;"> (iPos </span><span style="color: #000000;">></span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">) </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> (iPos </span><span style="color: #000000;"><</span><span style="color: #000000;"> (Length( Str )</span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">) ) </span><span style="color: #0000FF;">do</span><span style="color: #000000;"> </span><span style="color: #0000FF;">begin</span><span style="color: #000000;"><br /> </span><span style="color: #008000;">//</span><span style="color: #008000;"> If the new line starts with a Space or Tab, it's a continuation line</span><span style="color: #008000;"><br /></span><span style="color: #000000;"> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (Str[iPos</span><span style="color: #000000;">+</span><span style="color: #800080;">2</span><span style="color: #000000;">] </span><span style="color: #000000;">=</span><span style="color: #000000;"> #</span><span style="color: #800080;">9</span><span style="color: #000000;">) </span><span style="color: #0000FF;">or</span><span style="color: #000000;"> (Str[iPos</span><span style="color: #000000;">+</span><span style="color: #800080;">2</span><span style="color: #000000;">] </span><span style="color: #000000;">=</span><span style="color: #000000;"> #</span><span style="color: #800080;">32</span><span style="color: #000000;">) </span><span style="color: #0000FF;">then</span><span style="color: #000000;"> </span><span style="color: #0000FF;">begin</span><span style="color: #000000;"><br /> Delete( Str, iPos, </span><span style="color: #800080;">2</span><span style="color: #000000;"> );<br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;"> </span><span style="color: #0000FF;">else</span><span style="color: #000000;"> </span><span style="color: #0000FF;">begin</span><span style="color: #000000;"><br /> lstResult.Add( Copy( Str, </span><span style="color: #800080;">1</span><span style="color: #000000;">, Pred(iPos) ) );<br /> Delete( Str, </span><span style="color: #800080;">1</span><span style="color: #000000;">, Succ( iPos ) );<br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /> iPos :</span><span style="color: #000000;">=</span><span style="color: #000000;"> Pos( CRLF, Str );<br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /></span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /><br /></span><span style="color: #0000FF;">procedure</span><span style="color: #000000;"> TfrmHeader.adxOlFormADXSelectionChange( Sender: TObject );<br /></span><span style="color: #0000FF;">var</span><span style="color: #000000;"><br /> Selection: Outlook2000.Selection;<br /> IMail : _MailItem;<br /> IMessage : MAPIDefs.IMessage;<br /> PropValue: PSPropValue;<br /></span><span style="color: #0000FF;">begin</span><span style="color: #000000;"><br /> lbxHeader.Items.Clear;<br /> Selection :</span><span style="color: #000000;">=</span><span style="color: #000000;"> Self.ExplorerObj.Selection;<br /> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> Selection.Count </span><span style="color: #000000;">></span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;"> </span><span style="color: #0000FF;">then</span><span style="color: #000000;"> </span><span style="color: #0000FF;">begin</span><span style="color: #000000;"><br /> </span><span style="color: #0000FF;">try</span><span style="color: #000000;"><br /> </span><span style="color: #008000;">//</span><span style="color: #008000;"> Try for a "normal" mail item</span><span style="color: #008000;"><br /></span><span style="color: #000000;"> Selection.Item(</span><span style="color: #800080;">1</span><span style="color: #000000;">).QueryInterface( IID__MailItem, IMail );<br /> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> </span><span style="color: #0000FF;">not</span><span style="color: #000000;"> Assigned( IMail ) </span><span style="color: #0000FF;">then</span><span style="color: #000000;"> </span><span style="color: #0000FF;">begin</span><span style="color: #000000;"><br /> </span><span style="color: #008000;">//</span><span style="color: #008000;"> If it failed, try for a Read/Delivery Receipt item</span><span style="color: #008000;"><br /></span><span style="color: #000000;"> Selection.Item(</span><span style="color: #800080;">1</span><span style="color: #000000;">).QueryInterface( IID__ReportItem, IMail );<br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> </span><span style="color: #0000FF;">not</span><span style="color: #000000;"> Assigned( IMail ) </span><span style="color: #0000FF;">then</span><span style="color: #000000;"> </span><span style="color: #0000FF;">begin</span><span style="color: #000000;"><br /> </span><span style="color: #008000;">//</span><span style="color: #008000;"> I don't use Remote Mail, but for completeness this should be tested also...</span><span style="color: #008000;"><br /></span><span style="color: #000000;"> Selection.Item(</span><span style="color: #800080;">1</span><span style="color: #000000;">).QueryInterface( IID__RemoteItem, IMail );<br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /> </span><span style="color: #0000FF;">except</span><span style="color: #000000;"> </span><span style="color: #008000;">//</span><span style="color: #008000;"> Ignore exceptions</span><span style="color: #008000;"><br /></span><span style="color: #000000;"> </span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> Assigned(IMail) </span><span style="color: #0000FF;">then</span><span style="color: #000000;"> </span><span style="color: #0000FF;">begin</span><span style="color: #000000;"><br /> </span><span style="color: #0000FF;">try</span><span style="color: #000000;"><br /> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> IMail.Sent </span><span style="color: #0000FF;">then</span><span style="color: #000000;"> </span><span style="color: #0000FF;">begin</span><span style="color: #000000;"><br /> IMail.MAPIOBJECT.QueryInterface(MapiDefs.IMessage, IMessage);<br /> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> Assigned(IMessage) </span><span style="color: #0000FF;">then</span><span style="color: #000000;"> </span><span style="color: #0000FF;">begin</span><span style="color: #000000;"><br /> </span><span style="color: #0000FF;">try</span><span style="color: #000000;"><br /> PropValue :</span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">nil</span><span style="color: #000000;">;<br /> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> HrGetOneProp(IMessage, PR_TRANSPORT_MESSAGE_HEADERS, PropValue) </span><span style="color: #000000;">=</span><span style="color: #000000;"> S_OK </span><span style="color: #0000FF;">then</span><span style="color: #000000;"> </span><span style="color: #0000FF;">begin</span><span style="color: #000000;"><br /> StringToList( PropValue^.Value.lpszA, lbxHeader.Items );<br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /> </span><span style="color: #0000FF;">finally</span><span style="color: #000000;"><br /> MAPIFreeBuffer(PropValue);<br /> IMessage :</span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">nil</span><span style="color: #000000;">;<br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /> </span><span style="color: #0000FF;">finally</span><span style="color: #000000;"><br /> IMail :</span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">nil</span><span style="color: #000000;">;<br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;"> </span><span style="color: #0000FF;">else</span><span style="color: #000000;"> </span><span style="color: #0000FF;">begin</span><span style="color: #000000;"><br /> </span><span style="color: #008000;">//</span><span style="color: #008000;"> If no headers found...</span><span style="color: #008000;"><br /></span><span style="color: #000000;"> lbxHeader.Items.Add( </span><span style="color: #800000;">'</span><span style="color: #800000;">This type of message does</span><span style="color: #800000;">'</span><span style="color: #000000;"> );<br /> lbxHeader.Items.Add( </span><span style="color: #800000;">'</span><span style="color: #800000;">not have mail headers</span><span style="color: #800000;">'</span><span style="color: #000000;"> );<br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /> </span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /></span><span style="color: #0000FF;">end</span><span style="color: #000000;">;<br /><br /></span><span style="color: #008000;">(*</span><span style="color: #008000;"> Test Comment </span><span style="color: #008000;">*)</span><span style="color: #000000;"><br /></span><span style="color: #0000FF;">initialization</span><span style="color: #000000;"><br /> </span><span style="color: #008000;">(*</span><span style="color: #008000;"> Another test comment<br /> spanning 2 lines </span><span style="color: #008000;">*)</span><span style="color: #000000;"><br /> RegisterClass(TPersistentClass(TfrmHeader));<br /> </span><span style="color: #008000;">(*</span><span style="color: #008000;"> Another comment w/ a<br /> { Nested comment }<br /> </span><span style="color: #008000;">*)</span><span style="color: #000000;"><br /></span><span style="color: #0000FF;">finalization</span><span style="color: #000000;"><br /> </span><span style="color: #008000;">{</span><span style="color: #008000;"> Another test of nested comments<br /> (* This is<br /> another one *)<br /> </span><span style="color: #008000;">}</span><span style="color: #000000;"><br /></span><span style="color: #0000FF;">end</span><span style="color: #000000;">.<br /></span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div><br /><p></p><br /><p><span style="font-weight: bold; font-size: 180%">Wrap up</span> </p><br /><p><font color="#ff0000"><em><strong>Edit: Check </strong></em></font><a href="http://memyselfanddelphi.blogspot.com/2007/09/windows-live-writer-and-pascal-code.html"><font color="#ff0000"><em><strong>this post</strong></em></font></a><font color="#ff0000"><em><strong> for the updated files.</strong></em></font></p><br /><p><br /><p><em><strong></strong></em></p>So, if you got kind of lost, go <strike>here</strike> to download the WLW code formatting plug-in then download <strike>this file</strike> which is my updated ActiproSoftware.Pascal.xml file and place it in the plugins\languages folder. Download <strike>this file</strike> and place it in the plugins folder overwriting the existing one (updated languages definition file for the plugin). And you're good to go! <br /><p></p><br /><p>From now on you'll be able to easily insert Pascal formatted code onto your WLW post!</p><br /><p>If you find some syntax formatting error, let me know: I'll fix whatever needs fixing and, in a couple days, I'll send this updated file to the plugin's author so he can update his plug-in and also to the component's vendor since they're providing this for free so they too can update their component.</p><br /><p>Have fun blogging about code... :)</p><br /><p><em>Note: Somehow, either this plug-in's fault or WLW beta 2 fault, extra empty lines were added to my post, so don't be surprised if you need to delete some extra lines after publishing... :)<br><br>Also, for no good reason, even though it was displaying properly in WLW, some spaces were removed from the code, either from publishing or from my editing of this post afterwards. Just added those extra spaces and will see if they stick after re-publishing...<br>Update: apparently did not work! :( Still, not a big issue so I won't be spending time on it for now...</em></p><br /><p><em>Yet another update: I'm now re-editing the post from within WLW: first time I try this!! It appears to work just fine, so I'll try to re-publish it from WLW and see if the missing spaces in the code somehow re-appear as they show nicely in WLW...</em></p><br /><p><em>Well, it appears to be the plug-in's fault for adding the extra space: probably some style change that was not undone. As for the spaces, as long as I don't edit the post in the browser they display correctly. I'll have to get back to work, so maybe later I'll check the generated html from the code plug-in and try to find the bug. Until then, just ignore the extra spacing that makes this post look a bit ugly... :)</p></em> Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com5tag:blogger.com,1999:blog-9040327036497268290.post-31306173185093397712007-06-15T12:16:00.001+00:002007-06-15T12:18:31.789+00:00Developing Office Add-ins the Easy Way - Part 3 of 2 (AKA: Yes, I do know how to count!)<p>Well, even though it's probably not the best use for my time judging from the <em>overwhelming</em> feedback I got on the previous 2 parts, it also doesn't take me that long to write this 3rd part of 2 so I'll do it anyway! :)</p> <p>I've fixed most (all?) of the blogger screw-ups with the formatting of my post and some incorrect color coding from using Steve Trefethen's Syntax Highliting page, and now I decided to add a couple files for easier download. <a href="http://fmadsoft.com/mmd/files/Insider_Source.zip">Here</a> you can find the zip file with nothing but the source code and the Extended Mapi units, and <a href="http://fmadsoft.com/mmd/files/Outlook_Insider_Setup.exe">here</a> you can find a nice setup made with <a href="http://www.jrsoftware.org/isinfo.php">InnoSetup</a> in a few minutes that will install the compiled add-in, register it, create a source subfolder with the source code in it and allow you to uninstall all this at any time should you want to. Just remember that you need to restart Outlook to have it acknowledge the newly installed add-in.</p> <p>Because I know that Blogger will again mess up my formating, I'm instead placing here a prt-scr of the InnoSetup script used for creating the installer: most of it was done through the wizard...</p> <p><a href="http://fmadsoft.com/mmd/images/DevelopingOfficeAddinstheEasyWayPart3of2_BA39/Inno.png" atomicselection="true"><img style="border: 0px none ;" alt="Inno" src="http://fmadsoft.com/mmd/images/DevelopingOfficeAddinstheEasyWayPart3of2_BA39/Inno_thumb.png" border="0" height="457" width="640" /></a> </p> <p>On a different note, Part 3 of Delphi in a Radical Build will be postponed for a while: my available time has dropped considerably and whenever I pick up on that 3rd part I'll have to redo the 1st two parts as I've recently had some data loss while trying to repartition my external HDD using a re-partitioning utility that had not let me down before... So, the amount of work involved in creating that part 3 of 3 would largely surpass my free time for a lot longer. Not all is lost however as at least I can read my own articles and recreate it: that's one nice side-effect of blogging about something! :)</p> <p>On another different note, is it my impression or the Windows Live Writer beta 2 (which I installed after finishing the previous 2 posts), lost the spell checker?? I could swear there was an option to spell check in the previous beta!</p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com3tag:blogger.com,1999:blog-9040327036497268290.post-21015144422368892242007-06-14T16:43:00.001+00:002007-06-15T11:34:22.039+00:00Developing Office Add-ins the Easy Way - Part 2 of 2 (AKA: The tutorial stuff...)<p>If you haven't read <a title="Blah, Blah, Blah" href="http://memyselfanddelphi.blogspot.com/2007/06/developing-office-add-ins-easy-way-part.html">Part 1</a>, I'd advise you to do so. In it you'll find some more information on these components and, more importantly, your <strong>20% discount coupon</strong> redeemable until the end of June 2007...</p> <h4>Step 1: Running the new Add-In Wizard</h4> <ol> <li>Fire up Delphi and choose File->New->Other, Delphi Projects->Add-In Express VCL->ADX Outlook Add-in. </li><li>Click Next and, for the project name, I'm using <strong>Insider</strong> and <strong>coInsider</strong> for the coClass Name. The first is used, guess what?, for the Project's name and the 2nd is used in Outlook's COM Addins dialog (Tools->Options->Other->Advanced Options) </li><li>Clicking next will show you the "Option Pages" step which is optional. <ul> <li>For this addin we'll just hit next again. For a more complex add-in, this would be where you'd create your own option pages. You can have option pages displayed as another tab on the Options dialog or by right-clicking all or some folders in outlook, say one for Inbox, other for Outbox: they are different types of dialogs serving different purposes and you can add as many as you like.</li></ul> </li><li>Hit next again and we'll be in the "Outlook 2007 Task Panes"; again, not of interest to us here so move along. </li><li>Click Next, Finish and we're done here.</li></ol> <h4>Step 1.5: More blah, blah, blah...</h4> <p>We now have a basic project that we'll add some meat to in order for it to do what we set out to. We could easily add an explorer or inspector command bar, but we don't need them for this project. An explorer command bar is one that is displayed on Outlook; an inspector command bar is displayed when you double-click some outlook item and "inspect" it in it's own window. Say, when you double click an e-mail message and another window pops up. You can have the inspector command bars only display for certain types of folders by simply setting a property, say, create an e-mail inspector bar that is displayed only when inspecting a mail message but not when viewing an appointment. And, of course, you can add as many as you want and add buttons, menus and other controls to them at will.</p> <p>Among other cool objects you can use (not needed for this add-in), are the TADX<AppNameHere>AppEvents, such as TADXOutlookAppEvents from where you can add your own handlers. Here's the list of OutlookAppEvents (these are global events: other components have their own events as well, but these are events that don't relate to a particular button being pressed or hotkey being used):<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC9ZmKqygAu1N1ZlIBgL8Kt5yeiecInyfmiCCeIK9koUstMEbxghzi0IvIn4fsPTmNL9ehl1t7JbBAIw13eNrpMLCbYwcnatbvcYNqNJLoHlXQCmMwjk3cXkVpiYCjI0rsblcWiWBv5bs/s1600-h/Bugger.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC9ZmKqygAu1N1ZlIBgL8Kt5yeiecInyfmiCCeIK9koUstMEbxghzi0IvIn4fsPTmNL9ehl1t7JbBAIw13eNrpMLCbYwcnatbvcYNqNJLoHlXQCmMwjk3cXkVpiYCjI0rsblcWiWBv5bs/s320/Bugger.png" alt="" id="BLOGGER_PHOTO_ID_5075970504363274402" border="0" /></a></p><ul><li><strong><em>OnItemSend</em></strong></li><li><strong><em>OnNewMail</em></strong></li><li><strong><em>OnNewMailEx</em></strong></li><li><strong><em>OnQuit</em></strong></li><li><strong><em>OnReminderFire</em></strong></li><li><strong><em>OnStartup</em></strong></li></ul><p></p> <p>BTW: Thanks to blogger messing up my formatting big-time, I had to shorten the list to just a few sample items so as not to have a whole lot of space wasted. Maybe I'll take a prt-scr later and update this...</p> <h4>Step 2: Adding some components and code</h4> <ol> <li>What we are now going to add is an "ADX Outlook Form" which is a small pane where we will be displaying the headers of the selected message, so go to File->New->Other, Delphi Projects->Add-In Express VCL and double click "ADX Outlook Form". </li><li>Save the form (I used <strong>uHeader</strong> for the unit name). </li><li>Add a TListBox, call it <strong>lbxHeader</strong> and set it to fill the form. </li><li>We need another component to control creation of these panes. Go on to the main project form (should be empty) and add a "TadxOlFormsManager". </li><li>In this component's events, add the following code to the "OnADXBeforeFormInstanceCreateEx" event: <pre style="color:white;"><span style="color: rgb(0, 128, 128);">1</span> <span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> args.FolderObj.EntryID </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> OutboxEntryID </span><span style="color: rgb(0, 0, 255);">then</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">2</span> <span style="color: rgb(0, 0, 0);"> args.Cancel :</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> true;<br /></span><span style="color: rgb(0, 128, 128);">3</span> <span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;</span></pre> </li><li>Let's add that OutboxEntryID as a protected property to the form (TAddInModule) of type string: <pre style="color:white;"><span style="color: rgb(0, 128, 128);">1</span> <span style="color: rgb(0, 0, 0);">property OutboxEntryID: string read FOutboxEntryID;</span></pre> </li><li>And the corresponding internal field to the private section of TAddInModule: <pre style="color:white;"><span style="color: rgb(0, 128, 128);">1</span> <span style="color: rgb(0, 0, 0);">FOutboxEntryID: string;</span></pre> </li><li>And a method to set the value in the protected section (not a setter method though!): <ul></ul><pre style="color:white;"><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">procedure</span><span style="color: rgb(0, 0, 0);"> SetOutboxEntryID;<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">procedure</span><span style="color: rgb(0, 0, 0);"> TAddInModule.SetOutboxEntryID;<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">var</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);"> nameSpace : Outlook2000.NameSpace;<br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);"> outboxFolder: Outlook2000.MAPIFolder;<br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">try<br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);"> nameSpace :</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> OutlookApp .GetNamespace ( </span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">MAPI</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);"> );<br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);"> outboxFolder :</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> nameSpace .GetDefaultFolder( olFolderOutbox );<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);"> FOutboxEntryID :</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> outboxFolder.EntryID;<br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);"> <span style="color: rgb(0, 0, 255);">finally</span><br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 0, 0);"> nameSpace :</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">nil</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);"> outboxFolder :</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">nil</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;</span></pre> </li><li>Now click the form and enter the following code to it's "<strong>OnAddInInitialize</strong>" event:<br /><pre style="color:white;"><span style="color: rgb(0, 128, 128);">1</span> <span style="color: rgb(0, 0, 0);">SetOutboxEntryID();</span><br /></pre></li><li>Finally, let's give the <strong>TadxOlFormsManager</strong> something to manage: double click it and add a new item. Set the following properties for that item:</li> <ol> <li><strong>ExplorerItemTypes</strong>-><strong>expMailItem</strong>, set to <strong>True</strong> as we want this form displayed on mail folders only; leave all others to false. </li><li><strong>ExplorerLayout</strong> set to <strong>elTopSubpane</strong>; (you can play around with it later if you want!) </li><li>And finally, let's link it to the form we created above: set <strong>FormClassName</strong> to our form created above. It will be available on the drop down as soon as you go into <strong>File->Use Unit</strong> and select our uHeader unit.</li></ol></ol> <p>If you build the project, register it and launch outlook, you'll see a blank new pane displayed: Sorry for the large, dimmed and blurred image: it's from my main outlook... :)</p> <p><a href="http://fmadsoft.com/mmd/images/DevelopingOfficeAddinstheeasywayPart2of_EF99/EmptyFrame2.png" atomicselection="true"><img style="border: 0px none ;" src="http://fmadsoft.com/mmd/images/DevelopingOfficeAddinstheeasywayPart2of_EF99/EmptyFrame_thumb.png" border="0" height="140" width="240" /></a> </p> <p>Also, if you notice, so far most of the code was related to adding an exception, that is, we wanted our form to display on mail folders, <strong>unless</strong> that folder is Outbox.</p> <p>Now it's time to add our real meat into this.</p> <h4>Step 3: Adding our application logic</h4> <ol> <li>Lets go back to our <strong>uHeader</strong> unit and add the following code to the <strong>onADXSelectionChange</strong> event:<br /><pre style="color:white;"><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">procedure</span><span style="color: rgb(0, 0, 0);"> TfrmHeader.adxOlFormADXSelectionChange( Sender: TObject );<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 255);">var</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);"> Selection: Outlook2000.Selection;<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);"> IMail : _MailItem;<br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);"> IMessage : MAPIDefs.IMessage;<br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);"> PropValue: PSPropValue;<br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);"> lbxHeader.Items.Clear;<br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);"> Selection :</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Self.ExplorerObj.Selection;<br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);"> IMail :</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">nil</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> Selection.Count </span><span style="color: rgb(0, 0, 0);">></span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 128);">0</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">then</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">try </span><span style="color: rgb(0, 0, 0);">//</span><span style="color: rgb(0, 0, 0);"> Try for a "normal" mail item<br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 0, 0);"> Selection.Item(</span><span style="color: rgb(128, 0, 128);">1</span><span style="color: rgb(0, 0, 0);">).QueryInterface( IID__MailItem, IMail );<br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">not</span><span style="color: rgb(0, 0, 0);"> Assigned( IMail ) </span><span style="color: rgb(0, 0, 255);">then</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);"> //</span><span style="color: rgb(0, 0, 0);"> If it failed, try for a Read/Delivery Receipt item<br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 0, 0);"> Selection.Item(</span><span style="color: rgb(128, 0, 128);">1</span><span style="color: rgb(0, 0, 0);">).QueryInterface( IID__ReportItem, IMail );<br /></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">18</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">not</span><span style="color: rgb(0, 0, 0);"> Assigned( IMail ) </span><span style="color: rgb(0, 0, 255);">then</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">19</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);"> //</span><span style="color: rgb(0, 0, 0);"> I don't use Remote Mail, but for completeness this should be tested also...<br /></span><span style="color: rgb(0, 128, 128);">20</span> <span style="color: rgb(0, 0, 0);"> Selection.Item(</span><span style="color: rgb(128, 0, 128);">1</span><span style="color: rgb(0, 0, 0);">).QueryInterface( IID__RemoteItem, IMail );<br /></span><span style="color: rgb(0, 128, 128);">21</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">22</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">except</span><span style="color: rgb(0, 0, 0);">//</span><span style="color: rgb(0, 0, 0);"> Ignore exceptions<br /></span><span style="color: rgb(0, 128, 128);">23</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">//</span><span style="color: rgb(0, 0, 0);"> QueryInterface may throw up an exception, but I don't recall under what condition it was<br /></span><span style="color: rgb(0, 128, 128);">24</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">//</span><span style="color: rgb(0, 0, 0);"> It was for some non->relevant item, i.e., one that we're not processing here<br /></span><span style="color: rgb(0, 128, 128);">25</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">//</span><span style="color: rgb(0, 0, 0);"> That's the bad thing of writing something and not documenting it properly when it happens!<br /></span><span style="color: rgb(0, 128, 128);">26</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">27</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> Assigned(IMail) </span><span style="color: rgb(0, 0, 255);">then</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">28</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">try<br /></span><span style="color: rgb(0, 128, 128);">29</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> IMail.Sent </span><span style="color: rgb(0, 0, 255);">then</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">30</span> <span style="color: rgb(0, 0, 0);"> IMail.MAPIOBJECT.QueryInterface(MapiDefs.IMessage, IMessage);<br /></span><span style="color: rgb(0, 128, 128);">31</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> Assigned(IMessage) </span><span style="color: rgb(0, 0, 255);">then</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">32</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">try<br /></span><span style="color: rgb(0, 128, 128);">33</span> <span style="color: rgb(0, 0, 0);"> PropValue :</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">nil</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">34</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> HrGetOneProp(IMessage, PR_TRANSPORT_MESSAGE_HEADERS, PropValue) </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> S_OK </span><span style="color: rgb(0, 0, 255);">then</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">35</span> <span style="color: rgb(0, 0, 0);"> StringToList( PropValue^.Value.lpszA, lbxHeader.Items );<br /></span><span style="color: rgb(0, 128, 128);">36</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">37</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">finally<br /></span><span style="color: rgb(0, 128, 128);">38</span> <span style="color: rgb(0, 0, 0);"> MAPIFreeBuffer(PropValue);<br /></span><span style="color: rgb(0, 128, 128);">39</span> <span style="color: rgb(0, 0, 0);"> IMessage :</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">nil</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">40</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">41</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">42</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">43</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">finally<br /></span><span style="color: rgb(0, 128, 128);">44</span> <span style="color: rgb(0, 0, 0);"> IMail :</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">nil</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">45</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">46</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">//</span><span style="color: rgb(0, 0, 0);"> If no headers found...<br /></span><span style="color: rgb(0, 128, 128);">47</span> <span style="color: rgb(0, 0, 0);"> lbxHeader.Items.Add( </span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">This type of message does</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);"> );<br /></span><span style="color: rgb(0, 128, 128);">48</span> <span style="color: rgb(0, 0, 0);"> lbxHeader.Items.Add( </span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">not have mail headers</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);"> );<br /></span><span style="color: rgb(0, 128, 128);">49</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">50</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">51</span> <span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;</span></pre> </li> <li>Now let's add the MAPI units to our project and to the uses clause in this form:<br /><pre style="color:white;"><span style="color: rgb(0, 128, 128);">1</span> <span style="color: rgb(0, 0, 255);">uses</span><span style="color: rgb(0, 0, 0);"> MapiDefs, MapiTags, MAPIUtil;</span></pre><span style="color: rgb(0, 0, 0);"></span></li><li>Now all that is left is to add that <strong>StringToList</strong> function I used to process the semi-colon formatted mail headers into a more readable list:<br /><pre style="color:white;"><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">procedure</span><span style="color: rgb(0, 0, 0);"> StringToList( Str: string; lstResult: TStrings );<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">//</span><span style="color: rgb(0, 0, 0);"> Convert a header string containing CR/LFs and TABs into<br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">//</span><span style="color: rgb(0, 0, 0);"> a stringlist where each new property starts on a new line<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">var</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);"> iPos : integer;<br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">const</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);"> CRLF </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> #</span><span style="color: rgb(128, 0, 128);">13</span><span style="color: rgb(0, 0, 0);">#</span><span style="color: rgb(128, 0, 128);">10</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);"> lstResult.Clear;<br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);"> iPos :</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Pos( CRLF, Str );<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);"> (iPos </span><span style="color: rgb(0, 0, 0);">></span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 128);">0</span><span style="color: rgb(0, 0, 0);">) </span><span style="color: rgb(0, 0, 255);">and</span><span style="color: rgb(0, 0, 0);"> (iPos </span><span style="color: rgb(0, 0, 0);"><</span><span style="color: rgb(0, 0, 0);"> (Length( Str )</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(128, 0, 128);">1</span><span style="color: rgb(0, 0, 0);">) ) </span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">//</span><span style="color: rgb(0, 0, 0);"> If the new line starts with a Space or Tab, it's a continuation line<br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(128, 0, 0);"></span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (Str[iPos</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(128, 0, 128);">2</span><span style="color: rgb(0, 0, 0);">] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> #</span><span style="color: rgb(128, 0, 128);">9</span><span style="color: rgb(0, 0, 0);">) </span><span style="color: rgb(0, 0, 255);">or</span><span style="color: rgb(0, 0, 0);"> (Str[iPos</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(128, 0, 128);">2</span><span style="color: rgb(0, 0, 0);">] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> #</span><span style="color: rgb(128, 0, 128);">32</span><span style="color: rgb(0, 0, 0);">) </span><span style="color: rgb(0, 0, 255);">then</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);"> Delete( Str, iPos, </span><span style="color: rgb(128, 0, 128);">2</span><span style="color: rgb(0, 0, 0);"> );<br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">begin</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 0, 0);"> lstResult.Add( Copy( Str, </span><span style="color: rgb(128, 0, 128);">1</span><span style="color: rgb(0, 0, 0);">, Pred(iPos) ) );<br /></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(0, 0, 0);"> Delete( Str, </span><span style="color: rgb(128, 0, 128);">1</span><span style="color: rgb(0, 0, 0);">, Succ( iPos ) );<br /></span><span style="color: rgb(0, 128, 128);">18</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">19</span> <span style="color: rgb(0, 0, 0);"> iPos :</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Pos( CRLF, Str );<br /></span><span style="color: rgb(0, 128, 128);">20</span> <span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">21</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 0);">;</span><br /></pre></li> </ol> <h4>And we're done!</h4> <p>Just build again, and re-launch outlook and you'll have something like this:</p> <p><a href="http://fmadsoft.com/mmd/images/DevelopingOfficeAddinstheeasywayPart2of_EF99/FilledFrame2.png" atomicselection="true"><img style="border: 0px none ;" src="http://fmadsoft.com/mmd/images/DevelopingOfficeAddinstheeasywayPart2of_EF99/FilledFrame_thumb.png" border="0" height="140" width="240" /></a> </p> <h4>Final thoughts and notes:</h4> <ol> <li>Don't forget that you can <span style="font-weight: bold;">regsvr32 dlllname.dll</span> or <span style="font-weight: bold;">regsvr32 -u dllname.dll</span> and any installer will do that for you if you mark the dll as self-registering.</li> <li>Don't forget that you'll need to close the application you're testing/compiling your add-in for, before you can compile it as the dll will be in use! :)</li> <li>If you look back, you'll see that you pratically never knew you were handling COM objects and that most of the code was for the application logic with part of the complexity in that arising from using Extended Mapi because Outlook's object model is a bit limited in some places... Creating Excel add-ins is even easier as you don't have to deal with Extended Mapi! ;) You will require some knowledge of the application's Object Model, but that comes out of the box in the form of some VBA help files that you can install with your Office.</li><li>I didn't show in this simple demo two other easy to implement features, mostly out of lazyness: adding toolbars/buttons/menus and option pages. Trust me (or don't trust and instead try for yourself!): those are very easy to implement!<br /></li> <li>Don't forget to take advantage of the <strong>20% discount</strong> coupon (see <a title="Blah, Blah, Blah" href="http://memyselfanddelphi.blogspot.com/2007/06/developing-office-add-ins-easy-way-part.html">Part 1</a>), and have fun Developing Office Add-ins the Easy Way!</li><li>Syntax highlighting done using Steve Trefethen's <a href="http://www.stevetrefethen.com/highlighter/default.aspx">Syntax Highlighter</a> and then manually tweaked the generated HTML to fix some coloring bugs.<br /></li></ol>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com0tag:blogger.com,1999:blog-9040327036497268290.post-27503527876943935492007-06-14T16:40:00.001+00:002007-06-14T17:25:34.860+00:00Developing Office Add-ins the Easy Way - Part 1 of 2 (AKA: Blah, Blah, Blah...)<p>Well, I first started thinking of doing this post in April, then, earlier in May, I thought of contacting the component vendor asking them for a special discount coupon that I could give you, the reader of this blog. They promptly gave me one that was good until the end of May, but, as you may suspect by now, I didn't have the time to make the post. Well, things are a bit easier now with Windows Live Writer, so I'll try to make this post today (edit: I finished this several "todays" after starting!). (And don't worry, I talked with them and they extended the <strong>coupon's</strong> <strong>validity</strong> to the end of <strong>June</strong>!...)</p> <p>So, how does one create an Office Add-in the easy way? Well, you cheat! :)<br />Actually, it's no more cheating than using database access components to access a, (you guessed!) database... I've been using <a title="Add-In Express" href="http://www.add-in-express.com/">AfalinaSoft's Add-In Express</a> components in the last 18 months or so, and all I can say is that it's child's play doing any office Add-In development, be that Word, Excel, PowerPoint, Publisher, Visio, etc... I've created some Excel add-ins for my own use just because it was so easy to do them, rather than coding in VBScript! Outlook is <strong>very</strong> well represented in this lot with very cool features available for it as you'll see later in this post. Some new features added in the 2007 version allow you to add new <a title="Outlook Form Regions" href="http://www.add-in-express.com/outlook-extension/">form regions</a> allowing you to create some great outlook add-ins with very little effort! (Note: that's 2007 version of the components, not of Office! All the features and the tutorial in the next part work the same from Office 2000 to 2007!)</p> <p>Today's Add-In (I don't imply I'll be adding more, but one never knows as it's really easy to do them!), is a small Outlook Add-in that will show a collapsible pane in the messages list to show you the full Internet headers of the selected e-mail. You can shrink/expand/collapse this pane at will and, due to the way things work in Outlook, it's available for all mail folders except the Outbox. I've had to explicitly exclude that one after I found out that, if I select a message pending delivery, it would cancel delivery of that message: kind of what happens if you double click a message in the outbox and don't hit send again. No big deal: after a mail to the excellent Afalina support, I had a simple way of excluding just that folder (or any other I could want to exclude).</p> <p>So, what do you <strong>gain</strong> by using <a title="Add-In Express" href="http://www.add-in-express.com/">Afalina's Add-In Express</a> instead of doing it the hard way?</p> <ol> <li>A very well though out and tested component suite. </li><li>You can easily follow a couple steps in a wizard, add a few lines of code and have an add-in ready in minutes, not hours. </li><li>For the most part (there are a couple minor things to take into consideration), you get <strong>not</strong> to worry if your add-in is going to be used in Office 2000/XP/2003/2007 and wether or not those are running the default install or SP1 or SP2 or whatever. </li><li>If you plan on going the .NET way in the future, they have the exact same components available for .NET. </li><li>Deploying your add-in for non-.NET versions is easy: if you don't use packages, all get's compiled onto your main project (DLL), so it's a simple file to distribute/register/whatever. </li><li>Many examples of different add-ins for different office applications are available. </li><li>If you purchase the higher version (<strong>Premium</strong>), you get the <strong>full source code</strong>, including <strong>designers and wizards</strong>. </li><li>Again, for the highest version you can even have instant messaging access to the developers; for other versions, normal e-mail and web-forum based support is provided and still they answer questions promptly.</li></ol> <p>Now, before you read any further, I must point out three flaws of this component suite, even though they are minor flaws as I'll explain later:</p> <ol> <li>No trial version </li><li>Requires Activation </li><li>No help file</li></ol> <p>Why do I say they are minor?</p> <ol> <li>You have a no questions asked 30 day money back guarantee (for the non-source versions) : I recommend you start with Standard version or Basic if you're on a short budget, and later, after you decide you will keep it, contact them for upgrade pricing for the source-code versions. I started with Basic myself, over 18 months ago, and have since upgraded to the Premium for the source code and added support. </li><li>In the Premium version you get the whole source, even for the designers and wizards, so even if they somehow get out of business, you are not prevented from installing these components; also, you can install these on up to three machines, so you can install it on a Virtual Machine to have ready as a fallback procedure. </li><li>They provide an easy to follow start up manual, they also provide both in the installer and in their website a plethora of demo add-ins, they have a very active and friendly forum, and tech support is among the best I've found for any component suite. In fact, should you get the Premium package, you can even contact them through instant messaging!</li></ol> <p><span style="color: rgb(0, 0, 255);">As for the <strong>coupon</strong> code, if you purchase the <strong>Basic</strong> or <strong>Standard</strong> versions (<strong>no source code</strong> included), you can use this coupon for a <strong>20% discount</strong> until the end of June 2007: </span><span style="color: rgb(255, 0, 0);"><strong>ADFXM20</strong></span></p> <p><span style="color: rgb(255, 0, 0);"><span style="color: rgb(0, 0, 0);">Remember that, even using this coupon, you will still have the 30 days from date of purchase to return the product for the price paid should you not be happy with it.</span></span></p> <p>You will need the Standard version if you want to take advantage of the advanced forms feature as described in the next post. As for later, once you decide you want to keep these components and no longer need to take advantage of the money back guarantee, I'd recommend you to <strong>upgrade</strong> to either Pro or even better, Premium, not only for the full source code but also the added support. Contact them and they'll upgrade your license for the difference between the purchased and wanted versions.</p> <p>Now, with a very lengthy post already, it's time to start explaining how easy it is to create an outlook add-in to display the selected message's headers in another pane. When I started trying to create this demo application, I needed access to some message properties that I wasn't finding through the outlook object model, so I e-mailed them my question and very promptly (next day, IIRC), they sent me, not only the answer to my question, but a few Pascal units with the translated Extended MAPI <strong>and</strong> a <strong>sample project</strong> that addressed <strong>my</strong> problem! I received similar help from them later on when I couldn't find a way to exclude just one folder (outbox) from the folders where the add-in's pane would show and I mailed them the project with my question and they returned me the updated project with a few lines of code added and a short explanation of what was done. It's not as instant as a help file, but it sure is a lot more <strong>flexible</strong>!</p> <p>I was thinking of doing a Video, but not only I'm on a short budget now and the free solutions I tried didn't inspire me, but it's also easier to copy/paste this and print it out for reference, should you want to follow along!</p> <p><a href="http://memyselfanddelphi.blogspot.com/2007/06/developing-office-add-ins-easy-way-part_14.html">Part 2</a>, which I'm writing right now, will be posted a few seconds after part one: I decided to split it so it's not such a big article and because you can thus print that 2nd part and use as a follow along should you want to try it out.</p>Fernando Madrugahttp://www.blogger.com/profile/07296473246062338124noreply@blogger.com0