Я пытаюсь вызвать API C Nvidia Omniverse из моего приложения на базе .netcore.
Это API для загрузки файла. Договор вы можете найти здесь. https://docs.omniverse.nvidia.com/kit/docs/client_library/latest/_build/docs/client_library/latest/function_group__file_1gab649e472ef2238a89c4213357b1d5598.html#exhale-function-group-file-1gab649e472ef2238a8 9c4213357b1d5598
У меня недостаточно опыта работы с C, поэтому я не могу вызвать этот API.
Мои данные поступают с другого сервера как HttpContent.
Я уже написал этот код, но мое приложение аварийно завершает работу при обращении к API omniClientWriteFileEx. Подход 1:
public class test
{
[DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
static extern ulong omniClientWriteFileEx(string url, OmniClientContent content, IntPtr userData, IntPtr callback, string message);
public async Task UploadUsingCApiAsync(string url, HttpContent httpContent)
{
var data = await httpContent.ReadAsByteArrayAsync();
var content = new OmniClientContent
{
Buffer = content,
Size = content.Length
};
omniClientWriteFileEx(url, content, IntPtr.Zero, IntPtr.Zero, "");
}
private struct OmniClientContent
{
public int Size;
public Byte[] Buffer;
}
}
Подход 2
public class test2
{
[DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
static extern ulong omniClientWriteFileEx(string url, OmniClientContent content, IntPtr userData, IntPtr callback, string message);
public async Task UploadUsingCApiAsync(string url, HttpContent httpContent)
{
var data = await httpContent.ReadAsByteArrayAsync();
var content = await dssHttpContent.ReadAsByteArrayAsync();
var buffer = Marshal.AllocHGlobal(content.Length);
Marshal.Copy(content, 0, buffer, content.Length);
var content = new OmniClientContent
{
Buffer = buffer,
Size = content.Length
};
omniClientWriteFileEx(url, content, IntPtr.Zero, IntPtr.Zero, "");
}
private struct OmniClientContent
{
public int Size;
public IntPtr Buffer;
}
}
Я могу вызывать другие API этой библиотеки, где типы данных являются примитивными, но этот использует буфер.





В документах говорится:
Эта функция берет на себя управление буфером контента и освобождает его, когда закончит работу с ним (что может произойти через некоторое время в будущем).
Таким образом, вы не можете просто передать ему массив, потому что маршаллер открепит его после окончания вызова. Вам необходимо создать собственный буфер и самостоятельно маршалировать данные.
Сначала объявите все PInvoke следующим образом. Обратите внимание, что вам не хватает объявлений CharSet.Ansi и вам нужно определение обратного вызова.
Третье значение в OmniClientContent — это обратный вызов для освобождения буфера.
[DllImport(dllPath, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern ulong omniClientWriteFileEx(
string url, OmniClientContent content, IntPtr userData,
OmniClientWriteFileExCallback callback, string message);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void OmniClientWriteFileExCallback(
IntPtr userData, OmniClientResult result, OmniClientWriteFileExInfo info)
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void FreeBufferCallback(IntPtr buffer);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
class OmniClientWriteFileExInfo
{
public string version;
public string hash;
}
class OmniClientContent
{
public IntPtr buffer;
public IntPtr size;
public FreeBufferCallback FreeBuffer = Marshal.FreeHGlobal;
public OmniClientContent(byte[] array)
{
this.size = array.Length;
this.buffer = Marshal.AllocHGlobal(this.size);
Marshal.Copy(array, 0, this.buffer, this.size);
}
}
enum OmniClientResult
{
ValuesHere
};
Тогда вы можете сделать
public async Task UploadUsingCApiAsync(string url, HttpContent httpContent)
{
var data = await httpContent.ReadAsByteArrayAsync();
var content = new OmniClientContent(data);
omniClientWriteFileEx(url, content, IntPtr.Zero, null, "");
}
запуск этого кода в Linux приводит к ошибке сегментации при вызове функции обратного вызова. Даже если я передам ноль в качестве входных данных. Знаете, в чем может быть проблема?
Похоже на несбалансированный стек. Дважды трижды проверьте все. Я пропустил Cdecl делегата. И убедитесь, что вы объявляете некоторые из них как class а не struct, чтобы получить указатели.
Большое спасибо за очень подробное описание. :) Я могу выполнить API после передачи делегата, чтобы освободить буфер.