Jérôme Laban

.NET Powered

Obscure abstraction stories

clock April 14, 2004 11:55 by author Jerome

Today, I was rating some students group for one of their project (called Zia, a Third Year project about creating an HTTP server) and they told me that they could not understand some very strange behavior of their software. To keep it short, they were having some really strange jumps from some functions to others, in some unrelated places. This is unusual, particularly when the function actually called is not the one that should be called in a virtual function context.

The thing is, about this project, that it is required to have an extensible way of dealing with functionalities of an HTTP server in the form of Modules or Plug-ins. In an object oriented way of seeing things, two methods exist :

  • The first one is about using static referencing of types in a DLL, by means of directives like __dllimport set on classes. This is an impracticable way for plug-in enumeration as this is "dynamic static" linking of functions, which is much like linking using a static library. An other problem with this kind of implementation is that it cannot be used to efficiently achieve abstraction using the C#-style (or java) interface because types are explicitly referenced from the dynamic library. Generally speaking, this is not a good choice (and this is also not portable).
  • An other one is about using a common interface (or fully abstract class, only pure virtual functions and no data members) shared by both plug-ins and the host, and allowing  plug-ins to create concrete instances of the common interface. This has multiple advantages :
    • The host only imports a few "C-Style" functions (generally declared as extern "C") used, for example, to create instances of concrete classes or to enumerate types that can be created by the module. This also removes the implications of the symbols decoration (or name mangling) generated by the C++ compiler, (By the way, the dependency walker is a great tool to see this)
    • Types Virtual Tables are automatically built using the DLL memory space, letting the C++ plumbing doing the job for the user,
    • It is also possible to enumerate, load or unload plug-ins on the fly,
    • And obviously, the host only relies on the interface exposed by a plug-in to use its services. This is not specific to this method, but rather an other way of using interfaces with a greater level of abstraction, because concrete types are not known by the host.

In many ways, true dynamic loading of DLLs using this method is better than the static one. But we’re not in a perfect world and this method also has its drawbacks, some being really vicious.

 

There are multiple ways for including the Runtime Library, which is a kind of libc that can be found under Unices. Actually there are three ways:

  • Including the “SingleThreaded” (ST) version of the library, which is mainly suited for applications that do not use threads,
  • Including the “MultiThreaded” (MT) version that is used when the application is MultiThreaded. RT functions are then optimized to be ThreadSafe, which is not the case for the ST version. This is a static version of the RT that is completely included in the final binary minus, of course, methods you do use.
  • Including the “MultiThreaded DLL” (MD) version – the mostly used version – that references the msvcr7x.dll file. (This changes depending on the C++ compiler. Actually, this used not to change but it created havoc so…) This is, so far, the best way of including the RT as it lightens the weight of binaries and has other implications I will discuss later on.

This parameter can be found in :

 

Project Properties / C/C++ / Code Generation / Runtime Library

 

There is a thing about DLLs and static variables: These are local to their modules (understand DLL in this context) and not the current process. In other words, including the RT as a static library in a plug-in/host context creates multiple “instances” of the static variables found in the RT. In particular, it creates independent versions of internal lists used to maintain heap memory allocations. These lists are used, for instance, by malloc or other memory allocation functions.

 

Knowing this, it becomes obvious that allocating one object from one module (some plug-in) and freeing it in an other module (say the host) leads toward freeing a pointer that does not exist in the destination module. There are many behaviors that can be observed:

  • The first – which the most common – is the RT assertion dialog box showing up and saying that the pointer being freed is not valid. Most programmers don’t really understand this message and choose to ignore it because they don’t understand it, which is not that good…
  • The second, found if debugging features of the compiler are deactivated, is a simple crash but a really hard bug to spot.

Back in the object oriented world, where everything is encapsulated, you can find that kind of code in the shared interfaces:

 

class IObject

{

public:

       virtual std::vector<int>   GetRefs() = 0;
};

 

Although this is completely correct, the problem with that kind of code is that the vector object itself is generally allocated on the stack (although it depends on the left value used in the assignation) but contained data is allocated on the heap. This is a hidden memory allocation that can cause trouble when using the Static MultiThreaded version of the RT, leading – when you are lucky – to a crash and when you’re not, the kind of behavior my students have been experiencing, like a partial destruction of the heap and/or the stack…

 

In other words: Use the “MultiThreaded DLL” version of the Runtime Library in all the binaries and static libraries of your projects.  Note that I insist heavily on the fact that the same runtime must be used everywhere, otherwise you’ll get a lot of strange linker warnings and errors. (This is mainly because the same symbols are not exposed in the same way, static and dll imported)

 

By the way, in the .NET world it is mandatory when using Managed C++ extensions, probably for the same reason…



SyncProxy, an implicit synchronizer

clock April 4, 2004 11:51 by author Jerome

A few days ago, I ran into an MVP article on the MSDN talking about synchronizing asynchronous calls to WebServices heading back to the GUI. Since asynchronous calls are processed in separate threads, it is not safe to call GUI methods directly from these. The article was describing how to create some sort of helper class (some call this an Agent or Pattern) that allows to hide the call to BeginInvoke, freeing the developper from creating many small methods that would only contain calls to BeginInvoke.

Back in dotnetSoul, I did not have to call WebServices - at least not in a repetitive way - but I had to synchronize calls from events generated by the netsoul core. These events are fired from asynchronous read operations on a network stream, which implies that consuming these from the GUI requires to synchronize the call to update some controls.

The old fashion way is to register a "standard" method which only calls the synchronous method via BeginInvoke with the same parameters :

    _chatRoom.UserJoined += new EventHandler(OnChatRoomUserJoined);

...

    private void OnChatRoomUserJoined(object sender, EventArgs args)
    {
         BeginInvoke(new SyncEventHandler(SyncChatRoomUserJoined), new object[]{ sender, args });
    }

    private void OnChatRoomUserJoined(object sender, EventArgs args)
    {
         // call the UI from there...
    }

What a waste of time and error prone way of doing many GUI synchronous calls, since the netsoul core exposes about 20+ events to consumers. You might notice I'm using a SyncEventHandler delegate. I'm using this delegate to avoid the BeginMethod to change the parameters passed in.

So reminding the class used to synchronize the calls to the UI, I though I could create some sort of Proxy class that could be used to both register the event and create the instance of the proxy. I then came up with this :

using System;
using System.Windows.Forms;

namespace Epitech.NetSoul.UI
{
    public delegate void SyncEventHandler(object sender, EventArgs args);

    public class SyncProxy
    {
        private Control             _control;
        private SyncEventHandler    _syncHandler;
        private EventHandler        _asyncHandler;

        public SyncProxy(Control control, SyncEventHandler syncHandler)
        {
            _control        = control;
            _syncHandler    = syncHandler;
            _asyncHandler   = new EventHandler(AsyncHandler);
        }

        // Implicit operator to allow an easy registering on events
        public static implicit operator EventHandler(SyncProxy proxy)
        {
            return proxy._asyncHandler;
        }

        // The asynchronous delegate, which calls the synchronous delegate through
        // BeginInvoke, if required.

        private void AsyncHandler(object sender, EventArgs args)
        {
            if(_control.InvokeRequired)
            {
                _control.BeginInvoke(_syncHandler, new object[]{ sender, args });
            }
            else
            {
                _syncHandler(sender, args);
            }
        }
    }
}

Which can be used like this :

    _chatRoom.UserJoined += new SyncProxy(this, new SyncEventHandler(OnChatRoomUserJoined));

This call creates the proxy then registers the asynchronous delegate from the proxy through an implicit cast to EventHandler. This way, there is only one event handler to create inside the destination form per event handled.



Windows Installer CleanUp Utility

clock April 2, 2004 11:54 by author Jerome

Microsoft met a mis à disposition un utilitaire permettant de nettoyer la base de registre des problèmes liés à l'utilisation de Windows Installer... Une solution lorsque certains logiciels ne veulent plus s'installer et lancent des erreurs étranges...

News Source: The Windows Installer CleanUp Utility




About me

My name is Jerome Laban, I am a Software developer and .NET enthustiast from Montréal, QC. You will find my blog on this site, where I'm adding my thoughts on current events, or the things I'm working on, such as the Bluetooth Remote Control Software for Windows Mobile.


Sign in