M
Mark Olbert
First off, the sympathy is for all you poor buggers out there who have to figure out how to marry
Managed Extensions for C++ onto your legacy code. My condolences; my brief experience with the
process leads me to believe the Microsoft hates all of its VC++ developers
Now, the question. I'm getting a NullReferenceException in a __gc class that wraps functionality in
a legacy C/C++ app (it's actually part of the Nero burning rom api).
The legacy API expects to be given a configuration structure that contains, among other things, a
pair of function pointers which the codebase calls at various times. After much hair-pulling, I came
up with the following:
__delegate bool IdleCallbackHandler( void* pUserData );
__delegate NeroUserDlgInOut UserDialogCallbackHandler( void* pUserData, NeroUserDlgInOut type, void*
data );
[StructLayout(Layout::Sequential)]
__gc public struct NeroIdleCallback
{
public:
IdleCallbackHandler* ncCallbackFunction;
void* ncUserData;
};
[StructLayout(Layout::Sequential)]
__gc public struct NeroUserDialogCallback
{
public:
UserDialogCallbackHandler* ncCallbackFunction;
void* ncUserData;
};
[StructLayout(Layout::Sequential)]
__gc public struct NeroSettings
{
public:
const char *nstNeroFilesPath;
const char *nstVendor, *nstSoftware;
const char *nstLanguageFile;
NeroIdleCallback* nstIdle;
NeroUserDialogCallback* nstUserDialog;
bool nstEnableOverburn;
DWORD nstOverburnSize;
};
I configure this structure, and the callback substructures, in the constructor of my wrapper class
as follows:
theSettings = new NeroSettings();
theSettings->nstNeroFilesPath = "NeroFiles";
theSettings->nstLanguageFile = "Nero.txt";
theSettings->nstEnableOverburn = false;
theSettings->nstOverburnSize = 0;
theSettings->nstIdle = new NeroIdleCallback();
theSettings->nstIdle->ncCallbackFunction = new IdleCallbackHandler(this, &Nero::FireIdleEvent);
theSettings->nstIdle->ncUserData = idleData;
theSettings->nstUserDialog = new NeroUserDialogCallback();
theSettings->nstUserDialog->ncCallbackFunction = new UserDialogCallbackHandler(this,
&Nero::FireUserDialogEvent);
theSettings->nstUserDialog->ncUserData = userdlgData;
theSettings->nstVendor = "ahead";
theSettings->nstSoftware = "Nero - Burning Rom";
Everything works fine during initialization, and in retrieving certain basic information from the
legacy codebase.
But when I call a legacy function that triggers the IdleCallback, I get the NullReferenceException:
void AvailableDrives( NERO_MEDIA_TYPE mtFlags )
{
// this next line blows up... but the IdleCallback gets called first
NERO_SCSI_DEVICE_INFOS* drives = NeroGetAvailableDrivesEx(MEDIA_CD, NULL);
...
}
The interesting part is the part mentioned in that comment: the IdleCallback method gets called,
and returns, but then the exception gets thrown.
And what's really interesting is that setting the ncCallbackFunction delegate/function pointer to
NULL in the NeroIdleCallback structure -- which forces the legacy codebase to NOT call the
IdleCallback -- avoids the exception.
Sorry for being so long-winded.
What I'm wondering is, am I handling the function pointer concept correctly here? Is it possible
that I've done something wrong so that when the callback returns, it tries to return to a place that
doesn't exist?
- Mark
Managed Extensions for C++ onto your legacy code. My condolences; my brief experience with the
process leads me to believe the Microsoft hates all of its VC++ developers
Now, the question. I'm getting a NullReferenceException in a __gc class that wraps functionality in
a legacy C/C++ app (it's actually part of the Nero burning rom api).
The legacy API expects to be given a configuration structure that contains, among other things, a
pair of function pointers which the codebase calls at various times. After much hair-pulling, I came
up with the following:
__delegate bool IdleCallbackHandler( void* pUserData );
__delegate NeroUserDlgInOut UserDialogCallbackHandler( void* pUserData, NeroUserDlgInOut type, void*
data );
[StructLayout(Layout::Sequential)]
__gc public struct NeroIdleCallback
{
public:
IdleCallbackHandler* ncCallbackFunction;
void* ncUserData;
};
[StructLayout(Layout::Sequential)]
__gc public struct NeroUserDialogCallback
{
public:
UserDialogCallbackHandler* ncCallbackFunction;
void* ncUserData;
};
[StructLayout(Layout::Sequential)]
__gc public struct NeroSettings
{
public:
const char *nstNeroFilesPath;
const char *nstVendor, *nstSoftware;
const char *nstLanguageFile;
NeroIdleCallback* nstIdle;
NeroUserDialogCallback* nstUserDialog;
bool nstEnableOverburn;
DWORD nstOverburnSize;
};
I configure this structure, and the callback substructures, in the constructor of my wrapper class
as follows:
theSettings = new NeroSettings();
theSettings->nstNeroFilesPath = "NeroFiles";
theSettings->nstLanguageFile = "Nero.txt";
theSettings->nstEnableOverburn = false;
theSettings->nstOverburnSize = 0;
theSettings->nstIdle = new NeroIdleCallback();
theSettings->nstIdle->ncCallbackFunction = new IdleCallbackHandler(this, &Nero::FireIdleEvent);
theSettings->nstIdle->ncUserData = idleData;
theSettings->nstUserDialog = new NeroUserDialogCallback();
theSettings->nstUserDialog->ncCallbackFunction = new UserDialogCallbackHandler(this,
&Nero::FireUserDialogEvent);
theSettings->nstUserDialog->ncUserData = userdlgData;
theSettings->nstVendor = "ahead";
theSettings->nstSoftware = "Nero - Burning Rom";
Everything works fine during initialization, and in retrieving certain basic information from the
legacy codebase.
But when I call a legacy function that triggers the IdleCallback, I get the NullReferenceException:
void AvailableDrives( NERO_MEDIA_TYPE mtFlags )
{
// this next line blows up... but the IdleCallback gets called first
NERO_SCSI_DEVICE_INFOS* drives = NeroGetAvailableDrivesEx(MEDIA_CD, NULL);
...
}
The interesting part is the part mentioned in that comment: the IdleCallback method gets called,
and returns, but then the exception gets thrown.
And what's really interesting is that setting the ncCallbackFunction delegate/function pointer to
NULL in the NeroIdleCallback structure -- which forces the legacy codebase to NOT call the
IdleCallback -- avoids the exception.
Sorry for being so long-winded.
What I'm wondering is, am I handling the function pointer concept correctly here? Is it possible
that I've done something wrong so that when the callback returns, it tries to return to a place that
doesn't exist?
- Mark