CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 5 of 5
  1. #1
    Join Date
    Sep 2007
    Posts
    20

    Question 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

  2. #2
    Join Date
    Nov 2002
    Location
    Foggy California
    Posts
    1,245

    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

  3. #3
    Join Date
    Sep 2007
    Posts
    20

    Talking 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

  4. #4
    Join Date
    Nov 2002
    Location
    Foggy California
    Posts
    1,245

    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

  5. #5
    Join Date
    Sep 2007
    Posts
    20

    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
  •  





Click Here to Expand Forum to Full Width

Featured