Monday, February 20, 2012

ISSCEStatusReporting interface - replication progress in C++

Hi,

I'm not sure if my previous post was in the right forum so, please accept my apologies if I'm doing "double" post.

I have created 3 years ago C++ class wrapper -MFC like- for SQL Server CE 2.0. I migrated those two months ago to support SQL Mobile.

Today, I would like to get notifications from Replication progression but I couldn't figure how to override ISSCEStatusReporting interface.

If anyone could give hint or sample code, it will be greatly appreciated.

Thanks in advance,

Regards,
Fabien.

The merge process will call methods on an interface to an object instance that you have provided to it (ISSCEStatusReporting*).

If may help if you are familiar with COM Events, I find that process and ISSCEStatusReporting to be similar in principle (if not in exact implementation). I only mention this as I was working on COM Events elsewhere before my work on this, and the two seemed to gel in my mind.

The merge instance (your pointer to ISSCEMerge) expects a COM pointer. ISSCEStatusReporting is the interface it 'expects' from that pointer and call on.

So: Create a basic C++ class, deriving it from ISSCEStatusReporting.
Because ISSCEStatusReporting is abstract, the new class must implement all abstract methods - QueryInterface, AddRef, Release as well as your handler methods for OnStartTableUpload, OnStartTableDownload and OnSynchronization. Your "On..." handler methods will do whatever you need or want them to do (log info, fire event, etc), but the first three should operate like they always do for COM objects, if only for correct operation if not actually out of necessity.

Simple example is below:
Caveats: It's worked for me on WM5 device (no emulator) building with VS2005. I'm still in testing though. I think it may be possible to Cancel with these events (return a HRESULT other than S_OK?!) but I'm not going that far. My own usage of the code below is a little different as the class I use to manage the merge is itself the one providing the ISSCEStatusReporting interface. Because of this I've 'played' with the AddRefs.
Notes: It's useful to add TRACE statements or your equivalent while testing this, just to monitor what's going on. Be aware that this class will destroy itself when its ref count == 0, which should occur when you release your merge instance. Monitor TRACE output to find out? Let me know how you get on, hope this helps.

class myReporter : public ISSCEStatusReporting
{
private:
// reference counter
DWORD m_dwRefCount;
public:
// implement c'tor, d'tor, etc. and your own methods
// however this object is created, ensure dwRefCount == 0 at start
myReporter(...)
: dwRefCount(0)
{
...
}
virtual ~myReporter()
{
TRACE(L"~myReporter object being destroyed\n");
ASSERT(0 == dwRefCount); // should be no lingering references
}
// ISSCEStatusReporting
public:
// called during sync by SQL Server Mobile merge instance
STDMETHOD(OnStartTableUpload)(const WCHAR *wszTableName)
{
// do what you want here
TRACE(L"myReporter ::OnStartTableUpload: Table '%s'\n", wszTableName);
return S_OK;
}

// called during sync by SQL Server Mobile merge instance
STDMETHOD(OnStartTableDownload)(const WCHAR *wszTableName);
{
// do what you want here
TRACE(L"myReporter ::OnStartTableDownload: Table '%s'\n", wszTableName);
return S_OK;
}

// called during sync by SQL Server Mobile merge instance
STDMETHOD(OnSynchronization)(DWORD dwPrecentCompleted);
{
// do what you want here
TRACE(L"myReporter ::OnSynchronization: %2d%% complete\n", dwPrecentCompleted);
return S_OK;
}

// basic COM support (we're cheating a bit, but it will do)
STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject);
{
if (iid == __uuidof(ISSCEStatusReporting))
{
// we've been asked for an interface of type ISSCEStatusReporting
// which we support
TRACE(L"myReporter ::QueryInterface for ISSCEStatusReporting\n");
m_dwRefCount++;
*ppvObject = (void *)this;
return S_OK;
}

if (iid == __uuidof(IUnknown))
{
// we've been asked for an interface of type ISSCEStatusReporting
// which we support
TRACE(L"myReporter ::QueryInterface for IUnknown\n");
m_dwRefCount++;
*ppvObject = (void *)this;
return S_OK;
}

TRACE(L"myReporter ::QueryInterface for unsupported interface\n");
return E_NOINTERFACE;
}

// basic COM support (we're cheating a bit, but it will do)
STDMETHOD_(ULONG, AddRef)();
{
TRACE(L"myReporter ::AddRef()\n");
m_dwRefCount++;
return m_dwRefCount;
}

// basic COM support (we're cheating a bit, but it will do)
STDMETHOD_(ULONG, Release)();
{
TRACE(L"myReporter ::Release()\n");
ULONG l;

l = m_dwRefCount--;

if ( 0 == m_dwRefCount)
{
TRACE(L"myReporter ::Release() m_dwRefCount == 0 \n");
delete this;
}

return l;
}
};

// Usage
myReporter *rep = new myReporter();
rep->AddRef();
hr = pIMerge->put_StatusReportingHandler(rep);
// you should see another 'AddRef' TRACE, maybe the QueryInterface too
// run merge
// when finished:
rep->Release();

|||

Thanks you very much with that sample!

It will help me to compare what I finally succeed to get working yesterday afternoon and your great sample, with good trace and practices.

I was having a leak somewhere and I'm sure that I will nbe able to correct it with your help.

I was not such aware of AddRef when you do not get this class by QueryInterface...

Big thanks for my project,
Cheers, Fabien.

No comments:

Post a Comment