Tuesday, July 29, 2008
So to take a break from all my Delphi stuff, I figure I'll post about where I've spent most of my career, which is in healthcare. The majority of my experience comes in working with the VA's EHR, named VistA. VistA by the way, was created at least a decade before Microsoft Vista. Recently, I've become more interested in CHCS and AHTLA, which is part of the DoD EHR system. Interestingly, it seems that MHS (Military Health Systems) is turning to new web based technologies to gather feedback from their users. I'm glad to see some of the MHS leaders taking advantage of social technologies.
Wednesday, July 23, 2008
Congratulations to all who finished! My downfall was I bit off more than I could chew by using a semi-familiar IDE and language, while attempting to learn COM and WMI. No excuses though! Even though I couldn't finish the race, I had fun and I learned more about RAD Studio in the process.
My one regret is that due to all the problems to solve being GUI based, I couldn't enter using my best language, GT.M. I bet that would be something no one else has seen =P.
In any case, that's just me rambling on (and trying to find some way to work GT.M into my post). Too bad none of the people who finished the competition entered anything for OSX.
Sunday, July 20, 2008
For some odd reason, I thought that the competition ended on the 18th. It turns out it actually ends on the 22nd, so I still have more time to work on it. The next block of free time that I have will be on the 21st, so we'll see if I can work some magic to figure out WMI and COM before the actual deadline.
Friday, July 18, 2008
So I've been defeated by COM and WMI. To me, what's missing in the Delphi world are comprehensive tutorials and documentation like you can find with MSDN and Sun (for Java). What I ended up trying to do was look at existing code that uses WMI in Delphi, and attempt to reverse engineer it. I have a reasonable understanding of the objects and techniques used in the sample code, but when I got stuck, I had no idea what was causing the problem. Unfortunately, the time ran out for the competition before I could make anymore headway.
Earlier in the competition, I posted about my usual steps when learning something new, for the Darwin Race of Languages, I got stuck on step 2, developing the proof of concept, by reverse engineering existing examples.
If anyone is interested in looking at the code I was working on, the entire project is in a zip file here. Note that I'm not sure if all the imports will be correct on anyone elses pc, as the paths were local to my pc. I can't really call the code "my code", since it was mostly a cut and paste from someone named ciuly. I also used as reference, this project from Planet Source Code, which interestingly enough had errors, but ran on my workstation. When I attempted to extract the code and place it in my project, I ran into the same EOleException that I had in ciuly's example. That leads me to believe that the issue lies somewhere in my project, but not in the sourcecode.
Still no luck. All I can find are MSDN articles related to WMI on Microsoft's official languages, such as C++, C#, VB, etc. I can also find many examples of using WMI in Delphi, but there are no comprensive, newbie friendly tutorials on the different WMI components as related to Delphi and RAD Studio. I'm sure it's a simple fix to solve my problem, but those simple problems are the things that a newbie friendly tutorial will help walk me through.
When I was learning C#/.NET, I did most of my learning on MSDN. I've done multithreading, socket connections, registry modification, file encryption, used active directory, so on and so forth. I never once had to ask the wider .NET community for assistance, as MSDN has always been good to me. Ditto for learning Java, Sun's documentation is good as well (at least it was back when I was doing Java, the version 1 days).
RAD_Studio := IDE.Create('CodeGear');
Delphi := RAD_Studio.Language;
WMI := Component.Create('MS');
success := 'You Fail';
while OtherProjectsGoingOn do
if Solveable(Delphi, RAD_Studio, WMI, "2 weeks") then
success := 'yay!';
I've been reading through tons of examples of using WMI with Delphi, and I've tried running what seems like the most likely candidate for what I want to do (return the CPU temperature). However, I keep getting the error below.
It seems like I am unable to use Sinkclass.DefaultInterface when I call Services.ExecNotificationQueryAsync. Since the "Sink" is supposed to be an eventhandler that fires upon receipt of an event from Services, I guess this is a good error, since I don't have any code defined to handle the event, and I have absolutely no clue where DefaultInterface is in my Sink object.
I'm not sure if I will be able to complete the project before the deadline, but I'll keep trying until the time runs out.
Sunday, July 13, 2008
TStringList cannot handle spaces in its DelimitedText property. So the workaround is to ensure that your strings with spaces are enclosed in chars that are defined in the TStringList QuoteChar property. So what happens when you use the nifty LoadFromFile procedure on a large delimited text file with many spaces but no QuoteChars?
The answer is you get a messed up TStringList, because if you have no QuoteChars, TStringList assumes that spaces are delimiters too. Isn't that fun!
The parsing capabilities of TStringList are half-assed at best. In addition to the spaces/QuoteChars fiasco, your delimiter can only be a string with a length of one.
And don't worry, I've already programmed around TStringList's shortcomings. I had to load the file and parse it myself, adding quotes where necessary, then passing it to TStringList.DelimitedText.
Saturday, July 12, 2008
Whew, MSDN is always a tough read! So far all I have are a "Hello World" app, and I examined a sample project that I found here. That author uses ActiveX to query WMI, I think I may go the ODBC route as I'm more familiar with T-SQL. Here's a few screenshots of todays small progress.
Here's a screenshot of RAD Studio running inside of Parallels on OSX.
Here's a screenshot of the sample project files.
Here's a screenshot of the imports I did so that I can use WMI with my app. Note that there is an activex import there, I'm probably going to remove that and use ODBC as noted earler.
Here's a screenshot of my simple little hello world.
I'm not so sure on using ODBC now. I don't know if it's a good idea to assume that an end user will have MDAC installed on their machine.[/edit]
Friday, July 11, 2008
I figured out why uploaded pics are sometimes unclickable in Blogger. When you use Blogger's compose mode, and drag pics around your post, sometimes blogger loses the "a href" tag, and leaves behind the "img" tag. Thus, only a pic, no link. Just a handy tip in case anyone else was wondering.
So to take a break from constantly writing about Delphi and RAD Studio, here's a little bit about Dropbox. Dropbox is an online file storage application which interfaces seamlessly with Finder in OSX. It's actually pretty nifty to be able to work on remote files in exactly the same way as you would a local file. They probably use MacFuse to some extent on their backend.
Here's my Dropbox directory viewed on the web
Here's my Dropbox directory viewed in Finder
I've checked out the progress of some of the other competitors, seems like my late start has put me behind by a few days. That's alright though. My usual approach to a problem that I don't understand, is to do the following:
- Use my google-fu to do some research
- Get a proof of concept working
- Design the actual application
- Testing and refinement
So my rantings on Delphi and RAD Studio sort of spawned a programming/IDE competition hosted here. I got an invite to compete, and I figure... why not? The worst that could happen is I become better at RAD Studio and Delphi, which is a good thing. I'm sure the critics that I have would love to tear apart my code, and I'm going to give them that chance!
Thursday, July 10, 2008
The problem is solved! It was caused by me forgetting that Delphi is case insensitive, so I had a var named cParsedFile, and I tried to instantiate the object with a "cParsedFile := CParsedFile.Create;". I am really glad that the problem is in my code. If the problem is my code, then I can fix it! Kudos to Jørn Einar, and Bart Roozendaal for helping me figure it out, and thanks to Animal, Lars Fosdal, Thomas Müller and everyone else who gave assistance! This feels like I won some sort of award, and now I give my thank you speech ^_^.
To make up for my earlier comment, where I stated that RAD Studio was made by monkeys, here is a pic proving that RAD Studio was NOT made by monkeys.
Below are screenshots of a debugging session showing the visibility issue. I blacked out any proprietary code and information, hopefully still leaving enough code to show the problem I'm running into.
Here is my procedure, showing the var definition. Note that "global" is in the "uses" part of the implementation section.
Here we are in the constructor. Notice that now we are inside global.pas, this is the correct location for CParsedFile.Create.
The instant I hit "Step into" I get an access violation error. If you look at the code at the top of the constructor (above screenshot), you will see that it's nothing fancy, just a bunch of string assignments (these strings are defined in the class definition of CParsedFile in the implementation section of global.pas).
If I was referencing a separate var, or there was another definition of CParsedFile, why am I stepping into the correct constructor? If I edit my procedure so that "CParsedFile.Create" is now "global.CParsedFile.Create", and step through it, everything is fine. So you understand my frustration when:
- I can compile
- When I step through my code with the debugger, I get to the appropriate constructor
- I get a runtime error in the constructor
- This runtime error is fixed by prefacing the unit in front of my constructor call in my procedure.
For the project that I participate in, I usually work remotely through logmein, and that has been my only experience with RAD Studio. Trying to solve my visibility problem prompted me to install RAD Studio on my MacBook Pro through Parallels on Windows XP, so that I could work on code that I own and can post freely online.
Holy crap RAD Studio is fast, even though I'm running it through a virtualized OS. Now I just need to buy more ram so I can stop using virtual memory so much. I guess OSX + Firefox + Parallels + Windows XP will eat up 2GB =P.
So I can mark up one win for RAD Studio, it definitely executes faster than Visual Studio.
See... my experiences with Delphi and RAD Studio aren't all bad.
Tuesday, July 8, 2008
Believe me, I'm reading through them. I've been busy today so I haven't been able to look at that section of code again, but I'll get to it in the next few days and see if I can figure out (with the help of your comments) what was going on in my code.
Sunday, July 6, 2008
It's very clear to me that Visual Studio is the superior IDE compared to CodeGear RAD, and that is sad. Other Delphi programmers are constantly telling me how Microsoft gutted Borland's Delphi team, and hired away their best and brightest, including Anders Hejlsberg. Well you know what, all of Anders' creativity and talent are being put into C# right now. So it's no surprise that to many people, C# and Visual Studio are superior to Anders' old projects, Delphi and CodeGear RAD (or Turbo Pascal, whatever you wanna call it). It's unfortunate that Borland lost the corporate power game against Microsoft, but nobody said life was fair.
So from one Delphi developer to another, I ask you to demand more from CodeGear (or Embarcadero). You want people like me to sing the praises of CodeGear RAD? The best way to do that is to make CodeGear RAD the SUPERIOR TOOL.
And what's with the unconditional love for Borland/CodeGear? Is it because they are the scrappy company vs the monolithic giant? Even Java fans routinely criticize Sun. And you know what? Sun responds. Not everyone is happy with the way Sun treats their community at times, but at least they try to change for their users.
If I can paraphrase one of the commenters on my blog, Donald Shimoda suggests that I'm not spending enough time learning about CodeGear RAD and Delphi before I started using it. He says that I should read a few books before attempting to code in Delphi.
I disagree with him. I implore developers out there to not settle for crappy IDE's, API's and languages. Back in the day, hardware was expensive, programmers were cheap, and the tools were written for the machines, not the programmer. Nowadays, hardware is cheap, programmers are expensive, and tools are written for the programmer, not the machine.
Remember this, all you other developers out there, the programmer is the expensive one, the important one. You have the power to demand more from your tools.
To whatever random Delphi people that might read this blog and think that my criticisms stem from me not using CodeGear RAD for any length of time, please understand that the project I'm working on is relatively complex. I'm converting 30 or so forms from VB to Delphi, doing bug fixes all along the way. I use it all, xml, datasets, all kinds of widgets, straight file manipulation, everything. If there's anything at all that I can discover about Delphi or CodeGear RAD to help me work on this project, I use it. It especially frustrates me when I KNOW there's a way to do something in .NET, but there's no counterpart in the Delphi API's. I usually end up having to manually code more in Delphi than I did in C#/.NET.
- Delphi has no foreach control statement.
- Delphi arrays are primitive datatypes (like C, or you can call it a pointer with offsets, just like C, whatever floats your boat). So if you want to search an array, you have to write the code to do it yourself. There's no array object types, so there's no myArray.Find(value). I imagine there's redundant array searching code in pretty much every Delphi app out there (unless you rolled your own API into a .dll and bring it with you to different projects).
- If I pass a dynamic array into a function, Delphi assumes that it is a static array when in the function.
- Why doesn't ShowMessage automatically convert numerics to strings with an overloaded "+" operator? Oh it can, you say.... if I overload "+" myself... great.
- CodeGear RAD does not understand nested block comments. It takes the first end block comment, and applies that to the first start block comment. Nested block comments should function like nested parenthesis.
- Delphi has no automatic set/get declarations for accessing data inside a class. Not a big deal, but I thought it was nifty when C# added special syntax just for this.
Friday, July 4, 2008
So to balance out all the CodeGear hate, I decided to post some of the things that CodeGear RAD does well.
1. Uses the Delphi language - Delphi as a language is pretty nice to use. I particularly like how you are forced to declare your variables at the top of a function, it keeps your code cleaner. However, I would say that you should be able to declare your variables at the top of any section of code who's visibility is different from others. Case in point. If you are inside a "for" loop, you should be able to declare a variable that is accessible from only within the "for" loop. Current Delphi standards say that even though your intent is to only use this variable within the "for", you must declare it at the top of the function, where it is accessible to the entire function.
2. Debugging - From my previous experience with Visual Studio, I was happy to see that CodeGear had debugging facilities that were just as strong as Visual Studio.
3. Wysiwig editor - Again, from my previous experience with Visual Studio, I was happy to see that CodeGear had a wysiwig editor that was similar to Visual Studio (believe me, I've read all the stuff about MS gutting Borland's development team to form .NET and C#, so I understand that there are similarities in the platforms and IDE's). My only complaint about the wysiwig editor for both Visual Studio and CodeGear RAD, is that there are components that have no visible display, but can be added to your form's gui anyways. Case in point, your data access components (TClientDataSet, etc.). To me, the display editor should be kept pure, and if the IDE wants to show you a graphical representation of non-graphical components, it should be on a separate screen, not intermingled with your display widgets.
4. Heavy use of Win32 API - From experiences with poorly documented 3rd party widgets, I try to stay as far away from 3rd party add-ons as I can. The only time I will use one is when the widget is so awesome that it solves a problem perfectly for me.
5. Usage of .NET - As far as I understand it, CodeGear is one of the only IDE's besides Visual Studio that can write code to .NET's CLR.
6. How similar it is to Visual Studio - Yes yes, I know the history. Delphi is the father of C#, CodeGear RAD (or whatever it used to be called) is the father of the modern Visual Studio. Still, the 2 IDE's are so similar that I could pick up CodeGear RAD and hit the ground running.
The main reason why I am so critical of CodeGear RAD, is because I have heavy experience with Visual Studio, .NET and C#, so I can see where CodeGear RAD falls short. It is only natural to compare the 2 platforms, given how much history they have together. Here's my feelings about Visual Studio vs CodeGear RAD summed up in a pic.
To expand on the visibility issues, when I set a breakpoint and attempted to debug my code, control would flow from "test := TestClass.Create;" in Form1 to the definition of TestClass in global.pas. It would actually step into the constructor, and bomb on the first line of executable code. If I commented out all the executable code in the constructor, it would bomb upon attempting to exit the constructor. If I didn't have the proper visibility to execute the constructor, why did CodeGear RAD's compiler allow me to compile at all, and why would it bomb upon attempting to EXIT the constructor, as opposed to ENTER the constructor (I shouldn't even have been able to enter the constructor if the visibility was wrong).
I just wasted a good 4 hours because of retarded behavior of CodeGear RAD. Lets say I have a form called Form1, and a file called global.pas. I define a custom class called TestClass in global.pas. In the "uses" section of Form1, I add global. In the implementation section of Form1, I have a procedure called Proc1. In the "var" section of Proc1 I declare "test: TestClass;". In the code section of Proc1, I write "test := TestClass.Create;".
I figure since "global" is in the "uses" section of Form1, I'm good to go with using "TestClass" in Proc1. I compile with no errors. When I run my app, I get an "access violation". I rack my brain and use all the google-fu at my disposal to figure out what I'm doing wrong. Cause obviously the fault lies with my code somewhere right? Wrong. I must use a "test := global.TestClass.Create;" in Form1. In order for it to run properly. I completely lose my fucking mind at this point.
In any programming language known to man, something is either visible to you, or it is not visible to you. There is no "well, you can see it at compile time, but not at runtime". If "TestClass.Create;" was NOT in the proper visibility, THE COMPILER SHOULD HAVE THROWN AN ERROR. If "TestClass.Create;" was IN the proper visibility, THE RUNTIME SHOULD HAVE EXECUTED PROPERLY.
I understand when I waste my time because of something I did. I can accept that. What I cannot accept is when someone else wastes my time. The group of monkeys that made CodeGear RAD need to go take a class in compiler theory.
Before anyone bitches at me, please read the paragraph above on visibility, and why the compiler should have thrown an error.
This is the 3rd crash in a week. Not my application crashing mind you, but CodeGear RAD crashing. I edited out any sensitive information in the pic below. If there weren't so many people using CodeGear RAD, I'm not sure I would trust it to create executables that would run well in production.
Upon restarting CodeGear RAD, here it is with the view changed (everything undocked).
Just for note: ONLY CodeGear RAD crashes on this box. Not IE, not MSSQL, not Visual Studio, not anything else. CodeGear RAD is the special one.