Tuesday, September 16, 2008

Extract all files from MSI

msiexec /a msifilepath /qb TARGETDIR=folderpath

Example: msiexec /a c:\testfile.msi /qb TARGETDIR="c:\my test\"

Wednesday, July 30, 2008

'AG_E_RUNTIME_METHOD : Begin' error when starting a storyboard

Before starting animation, always make sure that animation objects and objects participating in the animation are added to the application's main object tree.
var myControl = plugIn.content.createFromXaml(a.loader.GetResponseText(part), true);
myControl.findName('myStoryBoard').Begin();
parentCanvas.children.add(myControl);

On Silverlight 1, this code will result an (infamous) error: AG_E_RUNTIME_METHOD : Begin

The solution is simple, add the created object first to main object tree and then start the animation:
var myControl = plugIn.content.createFromXaml(a.loader.GetResponseText(part), true);
parentCanvas.children.add(myControl);
myControl.findName('myStoryBoard').Begin();

This is obvious when looking to simple code like this, but in a bigger application it might not look so.
It's 'interesting' that in Silverlight 2.0 this error does not appear.

Thursday, March 13, 2008

vtable and __declspec(novtable) (aka ATL_NO_VTABLE)

__declspec(novtable) is a storage-class attribute and Microsoft specific applied to classes declaration.
It's purpose is to tell the compiler to not add the default vtable initialization\deinitialisation code in the class ctor\destructor.
When the compiler sees a class with virtual methods, it automatically adds vtable init\deinit code in the class ctor\destructor methods. Remember that the vtable is pointer to an array of pointers of the class virtual methods. I guess the initializatio is needed at the ctor time because at the time when your ctor method code is entered, the inner workings of the C++ object need to be initialized. Note that although the vtable is available on thee ctor code, its useless to use it, i.e. calling any virtual method. This is because the vtable of any derived class is not yet initialized.

So, using __declspec(novtable) we will not have the vtable initialized\deinitialized in the ctor\destructor methods.
This means that we cannot use the vtable in any way. More specifically, it means we cannot call any of the object's virtual method.

This has interesting effects. The obvious use is for interfaces, classes with pure virtual functions.

class __declspec(novtable) IFoo
{
public:
virtual ~IFoo()
{
}

virtual void foo() = 0;
};

class FooImpl : public IFoo
{
public:
virtual void foo();
};

IFoo* p = new FooImpl();
p->foo();

So the ctor\dctor of IFoo doesn't have any vtable initialization code as FooImpl has.
When we call foo() on the object the compiler sees that we use a pointer to an object and the method is virtual. Hence, it will use the vtable to get to the method. Vtable is a hidden pointer data in a class. It is always the first data when looking at the raw object in memory.
The FooImpl ctor initialized the vtable so the call is legit and always succeeds.
Remember that although the we call the Foo method of a pointer to IFoo, the vtable hidden data points to the FooImpl.
The vtable pointer is always the same in the raw object in all class derivations.

Another legit code is the following one:

class __declspec(novtable) A {
virtual void func1() { cout<<1; }
virtual void func2() { cout<<2; }
virtual void func3() { cout<<3; }
};

class A1 : public A {
// no func1, func2, or func3
};

It is OK to write:
A* p = new A1();
p->func1();
p->func2();
p->func3();

because A1 ctor initialize the object vtable.

And its NOT OK to write:
A* p = new A();
A->func1(); // undefined behaviour
p->func2(); // undefined behaviour
p->func3(); // undefined behaviour

It is OK to write:
A p;
p.func1();
p.func2();
p.func3();

because calling methods not using a pointer does not make use of vtable.

When using the novtable specifier, always think if the vtable is needed.
For example, you cannot use novtable for a class calling virtual methods in ctor\destructor. This is because the novtable told the compiler to omit the code which initialize the vtable before entering the ctor code.

This is very well described in the paper:
http://msdn.microsoft.com/msdnmag/issues/0300/c/

References in favor of pointers use

Always try to use reference instead of pointer to data wherever is possible.
A pointer to a data always raises the question if the pointer holds valid data, if it's 0 (NULL) for instance.
A reference shows that an object is passed and we don't do any data validation anymore, as for pointers.

// foo needs an instance of Foo
void foo(Foo* pF)
{
_ASSERTE(pF != 0);
....
}

// foo needs an instance of Foo
void foo(Foo& f)
{
....
}

It makes code writing and reading easier.

Using pointer variable is necessarily though in some situations.
You might want an optional parameter to your method:

// foo does NOT need an instance of Foo
void foo(Foo* pF)
{
if(pf != 0)
{
// use Foo object
....
}
else
{
// do something else in absence of a Foo object
...
}
}


This coding style and other good ones are mentioned in the paper http://www.research.att.com/~bs/JSF-AV-rules.pdf
The paper is mentioned on the home page of the father of C++.

Monday, February 04, 2008

MSI remember-to's

I am working with a wix installer and i needed to perform a specific task on uninstall.
After coding and compiling the msi, I tried to uninstall the product but I got a nasty error saying that the uninstallation cannot continue. The first thing i thought was 'shit, I cannot uninstall it'.
But here's a solution: MSI copies the original MSI file in the folder:
C:\WINDOWS\Installer
and the filename is in the form of 9c2ebd.msi
You can sort the files by 'Creation Date' if you know when did u install it.

I used then Orca editor to remove the uninstall custom actions which caused the uninstall to be unsucessful.

Also, another useful to know location is
C:\DOCUME~1\[user]\LOCALS~1\Temp
this is the location where the MSI log are written during installation\uninstallation. sort files by 'Creation Date'to see the log.

Thursday, November 15, 2007

RichEdit common contrl

i'll keep this post update with all the things about Rich Edit.

#1 The RichEdit Version

The current versions of RichEdit control and their modules are:

ver 1.0 contained in Riched32.dll
ver 2.0 contained in Riched20.dll
ver 3.0 contained in Riched20.dll
ver 4.1 contained in Msftedit.dll

The Rich Edit 3.0 (Riched20.dll) is included in releases of Microsoft Windows 2000 and above.

#2 Initialization
You need to explicitly load the RichEdit library in your application in order to use the control. Hence, to use the 3.0 version call:

if(NULL == LoadLibrary("RichEd20.dll"))
{
// cannot load RichEdit v3.0
}

Open and select a file in windows explorer

Many applications can open an windows explorer window an select a file. This is done by running explorer.exe with some command line switches.

There is a KB with the documented windows explorer switches:

The KB says that the supported versions include old OSes like Windows 95 but I think that 'select' switch for example works only for Windows XP and above.

Here is another KB for XP Windows Explorer.

A solution for older Windows OSes is to use Shell API i think.
I have not tried this but one solution would be to:
call CreateProcess( "explorer.exe" )
enumarate from ROT the windows explorer instances
connect to a instance and use the Shell API to navigate to the file.