Как правило, пользователи .NET вашей библиотеки не будут передавать динамически созданные массивы вашим функциям. Насколько я знаю, все контейнеры в .NET являются сборщиком мусора.
В любом случае вам нужно будет создать управляемую оболочку для вашего неуправляемого кода. На этот счет есть много учебных пособий и статей, здесь можно начать с .
При написании оболочек .NET для неизмененного кода я обнаружил, что вы хотите больше сосредоточиться на сохранении функциональности, чем на том, чтобы сделать каждую функцию доступной в .NET. В вашем примере может быть лучше, чтобы управляемая оболочка скопировала массив в неуправляемую память и выполняла все необходимые операции внутри библиотеки. Таким образом, вам не нужно делать какое-либо закрепление управляемой памяти или сортировку управляемой памяти на неуправляемую память, чтобы обойти сборку мусора во время выполнения .NET. Однако то, как вы реализуете управляемую оболочку, действительно зависит от цели этой функции.
Если вы действительно хотите реализовать эту функцию для функции в .NET, вам нужно взглянуть на класс Marshal в .NET для получения контроля над управляемой памятью в неуправляемом коде.
Для функции обратного вызова сначала необходимо создать делегаты .NET, которые можно назначать в управляемом коде. Затем вам нужно будет создать неуправляемую бесплатную функцию внутри вашей библиотеки, которая вызывается неуправляемой версией функции put. Эта неуправляемая свободная функция будет отвечать за вызов управляемого делегата, если пользователь назначил его.