Wednesday, May 24, 2006

Links Related to GUI Design Principles

HTML Dropdown Lists

Monday, May 22, 2006

Destructor Bug

I've got a problem: my VS6.0 C++ project won't build in Release mode. It complains about the destructor of a class declared in another DLL:

HEADTRL.OBJ : error LNK2001: unresolved external symbol "public: __thiscall TCIOControl::~TCIOControl(void)" (??1TCIOControl@@QAE@XZ)


So I look in the offending DLL with Depends.exe, and I find that the mangled name for the destructor differs by one character:

??1TCIOControl@@UAE@XZ


The U stands for virtual. The DLL that exports the symbol is a Debug DLL and the one importing is a Release DLL. So, why is the Release DLL looking for the non-vitual version of the exported class' destructor?

It turns out that whoever implemented the class pulled one of those #ifdef _DEBUG stunts. In Debug mode our imported class is given a base class, while in Release mode it's not.

By default, the VS6.0 compiler declares the destructor as virtual if the class has a base class, but does not otherwise.

So, by explicitly declaring the destructor as virtual (which is always a good idea) we restore Debug/Release binary compatibility.

Calling Conventions

Here is a link to an MSDN article describing the differences in behavior between various calling conventions. It outlines specifically:
  • The order in which parameters are pushed onto stack
  • Who is responsible for cleaning up stack (caller or callee)
  • Other deatails about register usage during function call

Name Mangling

Name mangling is a technique used by compilers to give programming entities (functions, structures, classes, etc.) unique names. Traditionally, the name given to a programming entity in the source file (i.e. function "foo") would be the name of the symbol in the object code. With modern programming languagues this simple approach cannot be used.

For example, operator overloading allows a developer to define a single function "foo" with multiple interfaces such as
void foo (int i);
void foo (char i);

While these two declarations have the same name, they are not the entity, and therefore should not be given the same symbolic name. The compiler must give each entity a unique name.

The name that a compiler chooses to give to a programming entity in order to preserve its symbolic uniqueness is called a mangled name or decorated name.

I use Microsoft's Visual Studio 6.0 compiler more often than any other. http://msdn2.microsoft.com/en-US/library/deaxefa7.aspx

Visual Studio 6.0 uses the following characteristics to create a mangled name for a programming entity:

  • Function Name
  • Parameters
  • Return Type
  • Calling Convention (__cdecl, __fastcall, __stdcall)

  • Use Depends.exe to view mangled symbols.
    Use Undname.exe to translate mangled symbols back into their human readable form.

    @@Uxx - "U" indicates that the entity is declared virtual
    @@Qxx - "Q" indicates that the entity is not virtual



    "There is currently no standard for C++ naming between compiler vendors or even between different versions of a compiler."


    References:

    IMPLEMENT_DYNAMIC / DECLARE_DYNAMIC

    IMPLEMENT_DYNAMIC and DECLARE_DYNAMIC are macros provided by Visual Studio for adding runtime type checking support to your CObject derived class.

    See this article on MSDN for an overview on adding run-time class information and other features to your CObject derived class.

    DECLARE_DYNAMIC declares the appropriate methods, and thus should be used in your class definition:
    class CPerson : public CObject
    {
    DECLARE_DYNAMIC( CPerson )

    // rest of class declaration follows...
    };


    IMPLEMENT_DYNAMIC implements the methodes, and thus should be used outside of your class definition:
    IMPLEMENT_DYNAMIC( CPerson, CObject )


    IMPLEMENT_DYNCREATE enables objects of CObject-derived classes to be created dynamically at run time when used with the DECLARE_DYNCREATE macro.

    Debugging Windows

    Setup VS 6.0 to Debug Windows DLLS
    Install VS 6.0 SP5
    Install VS 6.0 SP6
    Install WinNT Debug Symbols
    MFC Symbols can now be debugged

    Win32 Symbols are not working
    Try debugging under VS 2005... nope
    Install "Debugging Tools For Windows"... still no luck
    Set _NT_SYMBOL_PATH to
    SRV*e:\localsymbols*http://msdl.microsoft.com/download/symbols

    Friday, May 19, 2006

    Use the pre tag when displaying inline code snippets

    The pre tag preserves formmatting and does not eliminate white space (unlike the other tags which do eliminate whitespace). This is important when displaying inline code snippets so that code indenting is preserved.

    Another little note is that when using the div tag, CSS margins and padding is not preserved. I probably just don't understand HTML. Anyway, here are some examples:

    Using div:
    void foo ()
    {
    int a = -1
    return a;
    }


    Using pre:
    void foo ()
    {
    int a = -1
    return a;
    }


    Notice that when I use pre my indentation and margines are preserved, while they are discarded when using div.

    Well Paired Operations

    All "paired" operations should take place at the same level.

    What's a paired operation? An operation is paired with another operation if invoking one operation requires the other operation to be invoked. Examples:
    • malloc / free
    • new / delete
    • CreateDC / DeleteDC
    There are many others. The most problematic are the paired operations we ourselves create:
    • MyStartRoutine / MyStopRoutine
    What does it mean for paired operations to take place "at the same level"? Two operations are said to take place in the same context level if:
    • They occur in the same routine (i.e. in the immediate execution scope, not in a child routine)
    • They occur in two different routines who have the same degree of separation from a common ancestor
    • Others?
    Here is an example of a set of well paired operations:
    void foo ()
    {
    void * someData = malloc (10);

    // some code //

    free (someData);
    }
    The malloc and free operations are well paired because they occur in the same immediate execution context.

    Let's look at an example of a set of poorly paired operations. Aaside from the fact that the following code breaks about a billion other best coding practices it is a surprisingly common anti-pattern!
    void * formatSomeMemory()
    {
    void * tmp = malloc (10);

    // do some stuff

    return tmp;
    }

    void foo ()
    {
    void * someData = formatSomeMemory();

    // some code //

    free (someData);
    }

    In this context although the malloc and free operations share the same decendent routine - foo - they have differing degrees of separation and are therefore not well paired.



    So, who's fault is this? it's the author of formatSomeMemory()'s fault.

    Fundamentally, the problem of poorly paired operations is the result of poorly formed APIs. In this case, the author of the API that included the formatSomeMemory() routine did not provide an appropriate routine for freeing the data that formatSomeMemory allocated. The author of formatSomeMemory() is forcing the author of foo() to write poorly paired code!

    In reality, the author of formatSomeMemory() and foo() are probably the same person! The reason that this person wrote a poorly formed API is that they inadvertantly broke an even more fundamental well formed coding principle: The user of an API should not be required to have intimate understandings of the internal framework of the API in order to properly use it.

    In many cases, since the user is also the developer, this rule gets broken unconsiously. In our case, since the author of formatSomeMemory() knew that it malloc'ed some memory, he innocently added the free to foo and went on his merry way, not knowing he had just created a debugging pitfall for future developers.

    So, what might be some alternatives to the malformed API.

    Option 1 - Make user responsible for well pairing operations:
    void * formatSomeMemory(void * mem, int size)
    {
    // do some stuff to the memory
    // (perhaps even reallocing it)

    return tmp;
    }

    void foo ()
    {
    void * someData = malloc(10);

    someData = formatSomeMemory (someData, 10);

    // do stuff

    free (someData);
    }


    Option 2 - Handle well pairing behind the scenes:
    void * formatSomeMemory()
    {
    void * tmp = malloc(10);

    // do some stuff to the memory

    return tmp;
    }

    void * freeFormattedMemory (void * tmp)
    {
    free (tmp);
    }

    void foo ()
    {
    void * someData = formatSomeMemory ();

    // do stuff

    freeFormattedMemory (someData);
    }


    In both these examples the paired operations malloc amd free free are now well paired because in both cases they share the same degree of separation from the root routine foo.

    I personally prefer Option 1 to Option 2 simply because Option 2 requires good documentation to work properly. I hate documentation, don't you? :)

    Thursday, May 18, 2006

    Windows Device Contexts

    • An application cannot use the ReleaseDC function to release a DC that was created by calling the CreateDC function; instead, it must use the DeleteDC function. ReleaseDC must be called from the same thread that called GetDC.
    • The destructor of CDC will call DeleteDC on the device context associated with the CDC. In general, you don't need to call CDC::DeleteDC yourself.

    NetBeans Isuues


    The "/wizard.inf" issue is a known bug. It has to do with an old version of sax.jar residing in the /jre/lib/endorsed directory not being compatible with InstallShield. See the Netbeans.org bug reference.

    I receive this error when reinstalling Netbeans 4.0 or installing Netbeans Plugins.

    Temporarily renaming the entire endoresed directory to endoresed.bak during the install and then renaming fixed the problem.

    Thursday, May 11, 2006

    ip addr

    http://75.2.145.133/tsweb/

    Wednesday, May 10, 2006

    Development Links

    Tuesday, May 09, 2006

    Spectrum Build Notes

    When building any projects that use Automation.tlb the Automation project must be built first.

    Creating a Custom .NET Property Editor

    This How To explains how to create a custom editor for a property who's class cannot be edited by one of the built in VisualStudio Property Page editors.

    In general, a public property can be modified "at Design Time" by using Visual Stuio .NET's Property Page. Concider the following component:

    public class MyComponent : Component
    {
    private string myString;
    public string MyString
    {
    get { return myString; }
    set { myString = value; }
    }
    }

    Concider also that this component MyComponent were added to a user control, say MyControl. Using the Visual Studio control designer an instance of the component would appear at the bottom of the designer window.

    When designing a control, the user may manually set the values of properties of the components and controls contained in the control being designed. This is done by right clicking on a component or control, say MyComponent, and and selecting Properties. The Property Page window will show all the public properties for the control.

    In our case, the Property Page would show MyString and the user could then proceed to edit the property's value simply by entering a value next to the entry int the Property Page.

    CVS Server Configuration

    Thursday, May 04, 2006

    Windows Transparency

    A great article on the new features of the the Windows Presentation Foundation (WPF) can be found on MSDN. Many of the following quotes are taken from that article.

    "
    GDI+ offers partial transparency and anti-aliasing for drawing operations, but only when performed within the confines of a single control." - MSDN

    "With Win32, and the associated GDI and GDI+ drawing APIs, each control in the UI owns its part of the window exclusively. Windows are carved up by the controls into a set of disjointed regions that are usually, but not necessarily, rectangular. If you pick any single pixel on a window, there will be exactly one control responsible for drawing that pixel." - MSDN

    "WPF breaks free from this limitation. No single control or UI element has exclusive ownership of any part of the window in a WPF application. You can create partially transparent UI elements, or controls that are not visually constrained to their logical rectangle. For example, it's possible for a control to cast a shadow that falls outside of its logical region." - MSDN

    "In effect, the whole window becomes a single drawing surface that each of the parts of the UI contribute to." - MSDN

    Coding Quotes

    "I don't have a lot that is new, but I would say two things. First, if you look at interfaces in Java or .NET, in addition to being ABCs, interfaces also have no data. I have come to appreciate that if you use abstract base classes and eliminate any data from them, then a lot of the difficulties of multiple inheritance that I wrote about just go away, even in C++." - Scott Meyers

    Wednesday, May 03, 2006

    Memory, memory

    "Always delete what you new, and free what you malloc, never mix new with free or malloc with delete."

    The reason for this is that if you do that, then the behavior is technically undefined because there is no guarantee that new would internally use malloc, or that delete would internally use free.

    Also, never mix scalar new with vector delete. This will result in memory leaks.

    Test* t = new Test[3];
    delete t;


    I'm not sure that's right. I think delete t is OK.

    Or worse:
    Test* t = new Test;
    delete[] t;


    Why? Because the pointer returned by the new[] operator is not the start of the allocated memory but instead points to Test[0]. Huh? Isn't Test[0] the beginning of the memory block? N0! When using scalar new the complier keeps track of the number of items that have been allocated. This makes complete sense. However, we forget that part of the allocated memory includes this additional word of information! So in short - Vector New'd memory does not look like Scalar New'd memory!

    It's a little more clear when we take a look at the vector deleting destructor (pseudo-code):

    void MyClass::vector deleting destructor (int flags)
    {
    if (flags & 2) // vector destruct
    {
    size_t* a = reinterpret_cast(this) - 1;
    size_t howmany = *a;
    vector destructor iterator (p,
    sizeof(MyClass),
    howmany,
    MyClass::~MyClass);

    if (flags & 1) // vector delete
    {
    operator delete(a);
    }
    }
    else // scalar destruct
    {
    this->~MyClass(); // destruct one
    if (flags & 1) // scalar delete
    {
    operator delete(this);
    }
    }
    }



    "If you have to use strcpy, use strncpy instead!"

    char buf_a[16];
    char buf_b[256];
    ...
    strcpy (buf_a, buf_b);
    // This is really bad!


    The problem here is that the developer has forgotten that when using strcpy one must be aware of the size of the buffers being copied. By makeing a rule of always using strncpy instead of strcpy,