-
September 17th, 2007, 02:09 PM
#1
Trying to call a CLI function from native C++.
Hello again folks, I'm receiving this error:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
...when returning from a CLI function (whose parameter is considered "out of scope" for some reason).
Code:
MyClass
{
delegate void delegateOnTerminated(int State);
delegateOnTerminated^ _TerminatedDelegate;
void _internalOnTerminatedEventHandler(int);
GCHandle _TerminatedHandle;
delegate void OnTerminatedEventHandler(System::Object^ sender, MyClass::MyClassEventArgs^ e);
event OnTerminatedEventHandler^ OnTerminated;
};
how I bind the CLI member function to the native function pointer in MyClass ctor:
MyClass::MyClass()
{
_TerminatedDelegate = gcnew delegateOnTerminated(this, &MyClass::_internalOnTerminatedEventHandler);
_TerminatedHandle = GCHandle::Alloc(_TerminatedDelegate);
System::IntPtr DelegatePtr = Marshal::GetFunctionPointerForDelegate(_TerminatedDelegate);
OnTerminatedEvent nativeDelegatePtr = static_cast<OnTerminatedEvent>(DelegatePtr.ToPointer());
_stateNotifier->TerminationEventHandlers().push_back(nativeDelegatePtr);
}
Implementation of _internalOnTerminatedEventHandler:
void MyClass::_internalOnTerminatedEventHandler(int State)
{
MyClassEventArgs e = MyClassEventArgs();
switch(State)
{
case -1:
e.TerminationReason = CompletionType::Unfinished;
break;
case 0:
e.TerminationReason = CompletionType::Success;
break;
case 1:
e.TerminationReason = CompletionType::Cancelled;
break;
case 2:
e.TerminationReason = CompletionType::Unknown;
break;
default:
e.TerminationReason = CompletionType::Unknown;
}
OnTerminated(this, %e);
}
Now native:
Code:
nativeMain.h:
class nativeMain
{
private:
std::vector<OnTerminatedEvent> OnTerminatedEventHandlers;
public:
inline void OnTerminated(int State);
};
nativeMain.cpp:
void nativeMain::OnTerminated(int State)
{
int size = static_cast<int>(OnTerminatedEventHandlers.size());
if (size > 0)
{
for (int i = 0; i < size; ++i)
{
if (OnTerminatedEventHandlers[i] != 0)
{
OnTerminatedEventHandlers[i](State);
}
}
}
}
in a separate file:
typedef void (__thiscall *OnTerminatedEvent)(int);
Okay, so when calculations complete, OnTerminated(int State) is called, passing the completion state as an int parameter. OnTerminatedEventHandlers contains a pointer which is actually a manaqed member function of the CLI wrapper. The idea is that the native code calls the CLI function, the CLI function uses the parameter to throw a managed (and exposed) event which gets handled by C# UI code. I'm having two problems:
1) The parameter passed in to the CLI function is considered "out of scope" when debugging (why?).
2) The error mentioned at the beginning of this post.
Thanks,
Geoff
-
September 18th, 2007, 10:56 AM
#2
Re: Trying to call a CLI function from native C++.
I've had this very same problem. The problem is that by default, the calling convention for C++/CLI projects is __cdecl. However, the callback functions need to be declared __stdcall. Here is an example from my project (with names changed):
Code:
// C++ code
typedef void (__stdcall *MyEventHandler)(long* int32Info, long long* int64Info);
class MyClass
{
MyEventHandler eventHandler;
};
// C++/CLI
public ref class MyCppCliClass
{
delegate void EventDelegateType_(long* int32Info, long long* int64Info);
static EventDelegateType_^ eventhandlerDelegate_ = gcnew EventDelegateType_(eventHandler_);
MyClass* myClass;
void SetupDelegates()
{
IntPtr eventDelegatePtr = Marshal::GetFunctionPointerForDelegate(eventhandlerDelegate_);
myClass->eventHandler = static_cast<mpxcpplib::MeiEventHandler>(eventDelegatePtr.ToPointer());
}
};
I hope that helps!
- Kevin Hall
Kevin Hall
-
September 19th, 2007, 11:17 AM
#3
Re: Trying to call a CLI function from native C++.
Hi Kevin,
Thanks, a combination of your reply and this thread:
http://www.gamedev.net/community/for...opic_id=270670 (for [UnmanagedFunctionPointer(CallingConvention.Cdecl)] ) did the trick!
Geoff
-
September 19th, 2007, 11:46 AM
#4
Re: Trying to call a CLI function from native C++.
Glad I could help. That other thread is interesting. I didn't know this type of attribute existed:
Code:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
That may make life easier the next time I write a project.
- Kevin
Kevin Hall
-
September 19th, 2007, 12:19 PM
#5
Re: Trying to call a CLI function from native C++.
Oh, er, I should point out that my resultant working code (read: non-crashy) uses __cdecl in the typedef.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|