Update: Put a comment in if you want the C# version of this code and I will get it to you
Well, I was having troubles connecting to CVS on my
Managed BITS Sourceforge Project over my VPC, so while I figure it out, I decided to upload the source code plus binaries to
SaveFile for the time being. Let me know if you have any questions or problems regarding this.
Now that I got that out of the way, let's get back to where we left off. In the previous lesson, we talked about implementing the
IBackgroundCopyCallback interface. Since this interface also implements
IUnknown, we must also address that as well. I implemented the interface in a class called UnmanagedEventManager.
Let's take a look at the
IUnknown interface implementation first.
// Query interface method
HRESULT Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJobEventManager::UnmanagedEventManager::QueryInterface(REFIID riid, LPVOID *ppvObj)
{
// Check if IUnknown and IBackgroundCopyCallback
if (riid == __uuidof(IUnknown) || riid == __uuidof(IBackgroundCopyCallback))
{
*ppvObj = this;
} // if - riid
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
} // else - riid
// Add reference
AddRef();
return NOERROR;
} // method - UnmanagedEventManager::QueryInterface
// Add reference
ULONG Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJobEventManager::UnmanagedEventManager::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
} // method - UnmanagedEventManager::AddRef
// Release
ULONG Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJobEventManager::UnmanagedEventManager::Release()
{
// Decrement count
ULONG ulCount = InterlockedDecrement(&m_lRefCount);
// Delete if 0
if(0 == ulCount)
delete this;
return ulCount;
} // method - UnmanagedEventManager::Release
As you can see, we really did nothing special here. Just a standard plain-vanilla implementation of IUnknown. Now let's take a look at some of the methods that we must implement with the IBackgroundCopyCallback interface. We will note that the pCopyJobEventManager is of type gcroot<BackgroundCopyJobEventManager*>.
// Job error callback
HRESULT Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJobEventManager::UnmanagedEventManager::JobError(IBackgroundCopyJob __nogc* pJob, IBackgroundCopyError __nogc* pError)
{
// Call error event
pCopyJobEventManager->ErrorEvent(new BackgroundCopyJob(pJob), new BackgroundCopyError(pError));
return S_OK;
} // method - UnmanagedEventManager::JobError
// Job modification callback
HRESULT Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJobEventManager::UnmanagedEventManager::JobModification(IBackgroundCopyJob __nogc* pJob, DWORD dwReserved)
{
// Call modification event
pCopyJobEventManager->ModificationEvent(new BackgroundCopyJob(pJob));
return S_OK;
} // method - UnmanagedEventManager::JobModification
// Job transferred callback
HRESULT Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJobEventManager::UnmanagedEventManager::JobTransferred(IBackgroundCopyJob __nogc* pJob)
{
// Call transferred event
pCopyJobEventManager->TransferredEvent(new BackgroundCopyJob(pJob));
return S_OK;
} // method - UnmanagedEventManager::JobTransferred
Basically what these methods do is invoke the events when the IBackgroundCopyCallback is invoked from the
IBackgroundCopyJob interface. You have the ability to set the IBackgroundCopyCallback interface implementation through the
SetNotifyInterface and
SetNotifyFlags methods. The event implementations are quite simple as well and that code follows:
// The error event
void Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJobEventManager::ErrorEvent(Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJob* pErroredJob, Podwysocki::Services::BackgroundTransferServices::BackgroundCopyError* pCopyError)
{
if(this->pJobModificationEvent != NULL)
this->pJobModificationEvent->Invoke(this, new BackgroundCopyErrorEventArgs(pCopyError, pErroredJob));
} // method - BackgroundCopyJobEventManager::ErrorEvent
// The modified event
void Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJobEventManager::ModificationEvent(Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJob* pModifiedJob)
{
if(this->pJobModificationEvent != 0)
this->pJobModificationEvent->Invoke(this, new BackgroundCopyJobEventArgs(pModifiedJob));
} // method - BackgroundCopyJobEventManager::ModificationEvent
// The transferred event
void Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJobEventManager::TransferredEvent(Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJob* pTransferredJob)
{
if (this->pJobTransferredEvent != 0)
this->pJobTransferredEvent->Invoke(this, new BackgroundCopyJobEventArgs(pTransferredJob));
} // method - BackgroundCopyJobEventManager::TransferredEvent
It's important that we implement this class because we want a way to fire events upon completion of a job. As you can see, it's not entirely complex to translate the unmanaged code to managed, it just takes time and lines of code. Once again, the files are available from the link above, so let me know if you have any questions.