Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 449611
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 12, 20262026-05-12T21:47:12+00:00 2026-05-12T21:47:12+00:00

Introduction I am trying to use P/Invoke to register a struct of callbacks with

  • 0

Introduction

I am trying to use P/Invoke to register a struct of callbacks with a native dll. When calling a function that makes the native dll invoke the callbacks an AccessViolationException occurs. I have constructed a “small” test case that demonstrates the behavior comprised of 2 files, native.cpp that compiles into native.dll and clr.cs that compiles into the executable.

native.cpp


extern "C" {

typedef void (*returncb)(int i);

typedef struct _Callback {
    int (*cb1)();
    int (*cb2)(const char *str);
    void (*cb3)(returncb cb, int i);
} Callback;

static Callback *cbStruct;

__declspec(dllexport) void set_callback(Callback *cb) {
    cbStruct = cb;
   std::cout << "Got callbacks: " << std::endl <<
        "cb1: " << std::hex << cb->cb1 << std::endl <<
        "cb2: " << std::hex << cb->cb2 << std::endl <<
        "cb3: " << std::hex << cb->cb3 << std::endl;
}


void return_callback(int i) {
    std::cout << "[Native] Callback from callback 3 with input: " << i << std::endl;
}

__declspec(dllexport) void exec_callbacks() {
    std::cout << "[Native] Executing callback 1 at " << std::hex << cbStruct->cb1 << std::endl;
    std::cout << "[Native] Result: " << cbStruct->cb1() << std::endl;
    std::cout << "[Native] Executing callback 2 at " << std::hex << cbStruct->cb2 << std::endl;
    std::cout << "[Native] Result: " << cbStruct->cb2("2") << std::endl;
    std::cout << "[Native] Executing callback 3 with input 3 at " << std::hex << cbStruct->cb3 << std::endl;
    cbStruct->cb3(return_callback, 3);
    std::cout << "[Native] Executing callback 3 with input 4 at " << std::hex << cbStruct->cb3 << std::endl;
    cbStruct->cb3(return_callback, 4);
}

}

clr.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace clr {
    public delegate void returncb(Int32 i);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate int cb1();
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate int cb2(string str);
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void cb3(returncb cb, Int32 i);

    [StructLayout(LayoutKind.Sequential)]
    struct Callback {
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public cb1 c_cb1;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public cb2 c_cb2;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public cb3 c_cb3;
    }

    class Program {
        static int cb1Impl() {
            Console.WriteLine("[Managed] callback 1");
            return 1;
        }

        static int cb2Impl(string c) {
            Console.WriteLine("[Managed] callback 2");
            return int.Parse(c);
        }

        static void cb3Impl(returncb cb, Int32 i) {
            Console.WriteLine("[Managed] callback 3");
            Console.WriteLine("[Managed] Executing callback to native.");
            cb(i);
        }

        [DllImport("native.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void set_callback(ref Callback cb);

        [DllImport("native.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void exec_callbacks();

        static void Main(string[] args) {
            Callback cb;
            cb.c_cb1 = new cb1(cb1Impl);
            cb.c_cb2 = new cb2(cb2Impl);
            cb.c_cb3 = new cb3(cb3Impl);

            Console.WriteLine("Beginning test.");
            Console.WriteLine("Sending callbacks: ");
            Console.WriteLine("cb1: " + Marshal.GetFunctionPointerForDelegate(cb.c_cb1));
            Console.WriteLine("cb2: " + Marshal.GetFunctionPointerForDelegate(cb.c_cb1));
            Console.WriteLine("cb3: " + Marshal.GetFunctionPointerForDelegate(cb.c_cb1));
            set_callback(ref cb);
            exec_callbacks();
            Console.ReadLine();
        }
    }
}


Result

Invoking this results in exec_callbacks() throwing an AccessViolationException. cb1 is successfully invoked, but cb2 is not. Furthermore, the native code shows that before cb2 is called, its address has changed. Why does this occur? To the best of my knowledge, none of the delegates should have been gc’ed. As additionally information, marshalling a struct of IntPtr’s and using Marshal.GetFunctionPtrForDelegate works correctly (even for cb3 which gets a native ptr to invoke), however, being able to marshal the delegates directly makes more sense/is more readable.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-12T21:47:12+00:00Added an answer on May 12, 2026 at 9:47 pm

    The problem is that cb1, cb2 and cb3 are heap allocated, even though their storage (the struct) is not. Thus they are each subject to GC (compaction/relocation, thus invalidating the pointers originally passed in).

    Prior to passing in the struct, each of cb1, cb2 and cb3 should be pinned, ideally immediately after they are new’d. Otherwise they will likely relocate in memory.

    Was the decision to use a struct to contruct a classic function map done to avoid this relocation? If so, it’s ultimately non-helpful.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm trying to find a good, simple introduction to domain driven design, but that
I am trying out TYPO3's introduction package. For that I am using Xampp on
Introduction: I am trying to use CMake to obtain cross platform compilation scripts (for
Introduction: I'm trying to get additional fields to log with log4j, and its working
I'm trying to implement the example outlined here: http://www.codeproject.com/Articles/30994/Introduction-to-WPF-Templates The author states The ContentPresenter
I'm trying to learn redcode, because it looks fun to make a bot. Introduction
Introduction I have been so annoyed by applications that have a startup dialog which
I am trying to error check a form that on submitting creates an array,
I am trying to create a list view which as TextView that can display
I'm looking at the Ninject Factory extension at the following link: http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction/ I'm trying

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.