IMAPI how to register IDiscMasterProgressEvents

  • Thread starter Thread starter tonylc
  • Start date Start date
T

tonylc

Hey guys,
I got IMAPI to burn, but I would like to set up this progress events so
I can make a progress bar to go along with the burn process. Right now
I'm not exactly sure how to get this to work. I'm assuming I need to
implement the IDiscMasterProgressEvents interface, so I created my own
class and created empty stubs. Then I called the following code.

Code:

CDProgressEvents pDiscMasterProgressEvents;
...

// set up IDiscMaster, IDiscRecord, IJolietDiscMaster, etc...

HRSEULT hr =
pDiscMaster->ProgressAdvise(&pDiscMasterProgressEvents, progressID);


On the last line of code HRESULT keeps returning that a null reference
pointer was passed to the stub. Aren't I suppose to be passing an empty
object so that ProgressAdvise can fill it up? If that is not it, could
someone explain to me what I am doing wrong?

Thanks,
Tony
 
HRSEULT hr =
pDiscMaster->ProgressAdvise(&pDiscMasterProgressEvents, progressID);


On the last line of code HRESULT keeps returning that a null reference
pointer was passed to the stub. Aren't I suppose to be passing an empty
object so that ProgressAdvise can fill it up? If that is not it, could
someone explain to me what I am doing wrong?

Could you elaborate on 'progressID' ?
 
progressID is just a ID so I can pass it to a ProgressUnadvise call and
deactivate the notfication.
 
sorry to be more clear

this is the function header

HRESULT ProgressAdvise(
IDiscMasterProgressEvents* pEvents,
UINT_PTR* pnCookie
);

pEvents
[in] Pointer to an IDiscMasterProgressEvents interface that
receives the progress notifications.
pnCookie
[out] Uniquely identifies this registration. Save this value
because it will be needed by the ProgressUnadvise method.

I just create a UINT_PTR *progressID = 0;
and pass that into the function call.

I even tried using a local variable rather than a pointer..gave it some
junk id and passed in the address. HRESULT then gave me U_UNEXPECTED
return
 
sorry to be more clear

I just create a UINT_PTR *progressID = 0;
and pass that into the function call.

I even tried using a local variable rather than a pointer..gave it some
junk id and passed in the address. HRESULT then gave me U_UNEXPECTED
return

That last description is more what I was looking for. FWIW, this quick test
seems to go through the motions without error...

VOID _stdcall DXS_DMTest(VOID)
{
IDiscMaster* pidm = NULL;
HRESULT hr = CoCreateInstance(CLSID_MSDiscMasterObj,
NULL, CLSCTX_INPROC_SERVER|CLSCTX_NO_FAILURE_LOG,
IID_IDiscMaster, (VOID**)&pidm);

if (SUCCEEDED(hr) && (pidm))
{
hr = pidm->Open();
if (SUCCEEDED(hr))
{
IDiscMasterProgressEvents* piEvents = NULL;
hr = DXSDiscMasterProgressEvents::CreateInstance(&piEvents);
if (SUCCEEDED(hr) && (piEvents))
{
UINT_PTR uID = 0;
hr = pidm->ProgressAdvise(piEvents, &uID);
if (SUCCEEDED(hr) && (uID))
{
pidm->ProgressUnadvise(uID);
}
piEvents->Release();
}
pidm->Close();
}
pidm->Release();
}
}
 
I'm assuming DXSDiscMasterProgressEvents is just a simple stubbed class
that just calls the constructor. I did something similar, but on the
pass to ProgressAdvise, I'm getting E_UNEXPECTED in the return value.

I pretty much copied your code and am using it. So does that mean my
implementation of the IDiscMasterProgressEvents is wrong? Here is all
I have so far.


class CDProgressEvents : public IDiscMasterProgressEvents
{
public:

CDProgressEvents() {}
~CDProgressEvents() {}

HRESULT static
CDProgressEvents::CreateInstance(IDiscMasterProgressEvents **instance)
{
if (*instance == NULL)
{
*instance = new CDProgressEvents();
}
return S_OK;
}

ULONG STDMETHODCALLTYPE AddRef( void) { return 0; }
ULONG STDMETHODCALLTYPE Release( void) { return 0; }
HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void
__RPC_FAR *__RPC_FAR *ppvObject) { return E_NOTIMPL; }

HRESULT STDMETHODCALLTYPE QueryCancel(boolean *pbCancel);

HRESULT STDMETHODCALLTYPE NotifyPnPActivity()
{ return E_NOTIMPL; }

HRESULT STDMETHODCALLTYPE NotifyAddProgress(long nCompletedSteps,
long nTotalSteps);

HRESULT STDMETHODCALLTYPE NotifyBlockProgress(long nCompleted, long
nTotal);

HRESULT STDMETHODCALLTYPE NotifyTrackProgress(long nCurrentTrack,
long nTotalTracks)
{ return E_NOTIMPL; }

HRESULT STDMETHODCALLTYPE NotifyPreparingBurn(long
nEstimatedSeconds)
{ return E_NOTIMPL; }

HRESULT STDMETHODCALLTYPE NotifyClosingDisc(long nEstimatedSeconds)
{ return E_NOTIMPL; }

HRESULT STDMETHODCALLTYPE NotifyBurnComplete(HRESULT status)
{ return E_NOTIMPL; }

HRESULT STDMETHODCALLTYPE NotifyEraseComplete(HRESULT status)
{ return E_NOTIMPL; }
};

HRESULT STDMETHODCALLTYPE CDProgressEvents::QueryCancel(boolean
*pbCancel)
{ return E_NOTIMPL; }

HRESULT STDMETHODCALLTYPE CDProgressEvents::NotifyAddProgress(long
nCompletedSteps, long nTotalSteps)
{ return E_NOTIMPL; }

HRESULT STDMETHODCALLTYPE CDProgressEvents::NotifyBlockProgress(long
nCompleted, long nTotal)
{ return E_NOTIMPL; }
 
I'm assuming DXSDiscMasterProgressEvents is just a simple stubbed class
that just calls the constructor. I did something similar, but on the
pass to ProgressAdvise, I'm getting E_UNEXPECTED in the return value.

I pretty much copied your code and am using it. So does that mean my
implementation of the IDiscMasterProgressEvents is wrong? Here is all
I have so far.


class CDProgressEvents : public IDiscMasterProgressEvents
{
public:

CDProgressEvents() {}
~CDProgressEvents() {}

HRESULT static
CDProgressEvents::CreateInstance(IDiscMasterProgressEvents **instance)
{
if (*instance == NULL)
{
*instance = new CDProgressEvents();
}
return S_OK;
}

ULONG STDMETHODCALLTYPE AddRef( void) { return 0; }
ULONG STDMETHODCALLTYPE Release( void) { return 0; }
HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void
__RPC_FAR *__RPC_FAR *ppvObject) { return E_NOTIMPL; }

My guess is that your QI implementation is what is causing the problem. I
don't think QI is even allowed to return E_NOTIMPL. I didn't spend much time
on it, but FWIW, I implemented my event class like so...

class DXSDiscMasterProgressEvents : public IDiscMasterProgressEvents
{
public:
static HRESULT STDMETHODCALLTYPE
CreateInstance(IDiscMasterProgressEvents** ppEvents);
private:
DXSDiscMasterProgressEvents();
protected:
STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppv);
STDMETHOD_(ULONG, AddRef)(VOID);
STDMETHOD_(ULONG, Release)(VOID);
protected:
STDMETHOD(QueryCancel)(boolean *pbCancel);
STDMETHOD(NotifyPnPActivity)(VOID);
STDMETHOD(NotifyAddProgress)(LONG nCompletedSteps, LONG nTotalSteps);
STDMETHOD(NotifyBlockProgress)(LONG nCompleted, LONG nTotal);
STDMETHOD(NotifyTrackProgress)(LONG nCurrentTrack, LONG nTotalTracks);
STDMETHOD(NotifyPreparingBurn)(LONG nEstimatedSeconds);
STDMETHOD(NotifyClosingDisc)(LONG nEstimatedSeconds);
STDMETHOD(NotifyBurnComplete)(HRESULT status);
STDMETHOD(NotifyEraseComplete)(HRESULT status);
private:
ULONG m_cRefs;
};

DXSDiscMasterProgressEvents::DXSDiscMasterProgressEvents() : m_cRefs(0)
{
}

STDMETHODIMP
DXSDiscMasterProgressEvents::CreateInstance(IDiscMasterProgressEvents**
ppEvents)
{
HRESULT hr = E_NOINTERFACE;
if (!(ppEvents))
hr = E_POINTER;
else
{
DXSDiscMasterProgressEvents* pThis = new
DXSDiscMasterProgressEvents;
hr = pThis->QueryInterface(IID_IDiscMasterProgressEvents,
(VOID**)ppEvents);
}
return hr;
}

STDMETHODIMP DXSDiscMasterProgressEvents::QueryInterface(REFIID riid,
LPVOID* ppv)
{
HRESULT hr = E_NOINTERFACE;
if (!(ppv))
hr = E_POINTER;
else
{
*ppv = NULL;

if ((IID_IUnknown == riid) || (IID_IDiscMasterProgressEvents ==
riid))
{
*ppv = this;
AddRef();
hr = S_OK;
}
}
return hr;
}

STDMETHODIMP_(ULONG) DXSDiscMasterProgressEvents::AddRef(VOID)
{
return InterlockedIncrement((LONG*)&m_cRefs);
}

STDMETHODIMP_(ULONG) DXSDiscMasterProgressEvents::Release(VOID)
{
ASSERT(0 != m_cRefs);
ULONG cRef = InterlockedDecrement((LONG*)&m_cRefs);
if (0 == cRef)
{
delete this;
}
return cRef;
}

....and for all the IDiscMasterProgressEvents methods I do just return
E_NOTIMPL.
 
hey Jeff..I tested it out w/ your code..and it works. i'm didn't know
I had to set up the QI in a particular way. thanks for all your help =)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top