Solving I/O Error 103 in LoadXMLDocument

In a Delphi console application that reads its configuration from an XML file, I unexpectedly ran into “I/O error 103”. I/O error 103 will look familiar to most of you Delphi developers, it means “File not open”. I traced it to this source line:

xmlcfg := LoadXMLDocument(FConfigFilePath);

LoadXMLDocument comes from the Delphi unit XMLDoc.pas, so the problem was not in my code. Ouch, this could mean trouble. But, the exact same unit was used in another (Forms) application where it worked perfectly fine. What was going on here?

The solution was fortunately deceivingly simple: the XMLDoc unit uses interfaces, so you need a CoInitialize() call before doing anything. As it turned out, my CoInitialize() call was too late. It was further down, right before initializing some ADO components, but after the attempt to read the configuration file. So the solution was to put

CoInitialize(nil);

At the very top of my initialization code, before calling the configuration reader. Now it worked fine, no more “File not open” messages.

This proved once more that sometimes, the error message you get has little to do with the real issue at hand.

For reference: CoInitialize resides in the ActiveX unit.

Advertenties

Returning to previous editor tab in Delphi

Having done a lot of Visual Studio work lately, I’ve grown accustomed to the VS way of switching between open file tabs with the Ctrl+Tab keystroke: it switches between files in Most Recently Used order, the same way Alt+Tab does for open programs. This is extra easy when, while coding, you have to do a lot of switching back and forth between just two or three files. You can do so from your keyboard without reaching for your mouse.

I didn’t notice how much I’ve gotten used to it, until recently I had to do a lot of Delphi work again. Using Ctrl+Tab in Delphi also switches between tabs, but in the order the tabs are placed at the top of the editing window (mostly the order you loaded them in). While this is admittedly more predictable when you have lots of files open, in practice I find it much less useful. When I have lots of files (tabs) open, I rarely use the tabs at the tab to switch between files but instead use the Project Manager or hit Ctrl+F12 and start typing the unit name.

Looking for a Delphi equivalent of VS-like behavior for Ctrl+Tab (or a plugin that takes care of it), I stumbled upon this post by Joe White from a couple of years back. He mentions the use of Ctrl+B, which brings up a opened units list, but with the units sorted in MRU order, and with the focus already on the previously opened unit. Because of this, Ctrl+B followed by ENTER, immediately brings you to the window you previously were.

Ctrl+B brings up a unit list in Most Recently Used order, focusing the previously opened unit.

Ctrl+B brings up a unit list in Most Recently Used order, focusing the previously opened unit.

Summarized (Visual Studio -> Delphi)

  • Ctrl+TAB -> Ctrl+B, ENTER
  • Ctrl+TAB,TAB -> Ctrl+B, down arrow, ENTER
  • Ctrl+TAB,TAB,TAB -> Ctrl+B, down, down, ENTER
  • etc.

Still not exactly, but almost as good.

Keeping a modeless window accessible from a modal (dialog) window

In a C# WinForms application I was working on, users were effectively working with two more or less independent windows: one they worked in, and another that showed documents and other info they need to do that work. The problem was that when they were in a dialog, for example one to assist in creating a new object, the window holding the documents with info on the object was not accessible because the dialog is modal.

You can have the dialog take ownership of the document window, but that means also it will always be on top of it, which would be inconvenient.

So I borrowed a trick from my Delphi days that I found here. You only need to do a small Windows API call from your code. I added this code to utility class called FormsUtil, but you could of course put it anywhere that’s convenient to you.


[DllImport("user32.dll")]
private static extern bool EnableWindow(IntPtr hwnd, bool bEnable);

public static bool EnableWindow (Form form, bool enable) {
    return EnableWindow(form.Handle, enable);
}

This allows you to, in the dialog form, attach an event handler to the Shown event:

private void NewObjectForm_Shown(object sender, EventArgs e) {
    if (this.Modal) {
        var viewer = GetReferenceToDocumentViewerForm();
        FormsUtil.EnableWindow(viewer, true);
    }
}

Now the document viewer window is accessible from the “new object” dialog.

Tip: be careful if you ever choose to use EnableWindow(formX, false). It will disable that form completely, including not being able to close it.

SyncEdit for implementation/interface member parameters

When I am editing a method (procedure/function) of an object, I sometimes need to add a parameter or change some. Now in Delphi code, as you probably know, you often have to do that twice: once in the implementation, and once in the interface of the unit (and make sure it matches…).

The Change Parameters dialog - do you ever use it? Too cumbersome imo.

Of course you can use the change params refactoring (Ctrl+Shift+X), but personally I find it too cumbersome to use the dialog to change something that could much easier be typed. And did you notice that your cursor has to be on the method name, not the parameters that follow it, for the refactoring to even be enabled? Blegh. It just breaks my ‘flow’… Lees meer over dit bericht