2016-02-22 2 views
-1

Я использую C lib с C#. Это прототип функции, которую я хочу использовать:Использование неуправляемого C lib с C#

heatmap_render_default_to(const heatmap_t* h, unsigned char* colorbuf) 

Эта функция выделяет память для colorbuf так:

colorbuf = (unsigned char*)malloc(h->w*h->h * 4); 

называть свою функцию из C# Я пытался сначала создать неуправляемые памяти, как это:

string image = ""; 
//allocate from COM heap   
Marshal.StringToCoTaskMemAnsi(image); 
GCHandle gch = GCHandle.Alloc(image, GCHandleType.Pinned); 
HeatMap.HeatMapWrapper.NativeMethods.Render_default_to(hmPtr, image); 

Но я получаю это исключение: Exception брошенного в 0x0F17263A (E asyDLL.dll) в Test.exe: 0xC0000005: место записи нарушения доступа 0x01050000. Если для этого исключения есть обработчик, программа может быть безопасно продолжена.

Это первый случай, когда я пытаюсь интегрировать неуправляемую библиотеку в C#.

Может ли кто-нибудь помочь мне в этом?

PInvoke:

[DllImport(DLL, EntryPoint = "heatmap_render_default_to", CallingConvention = CallingConvention.Cdecl)] 
public static extern string Render_default_to(IntPtr h, byte[] colorbuf); 
[DllImport(DLL, EntryPoint = "heatmap_render_to", CallingConvention = CallingConvention.Cdecl)] 
public static extern string Render_to(IntPtr h, IntPtr colorscheme, byte[] colorbuf); 
[DllImport(DLL, EntryPoint = " heatmap_render_saturated_to", CallingConvention = CallingConvention.Cdecl)] 
public static extern string Render_saturated_to(IntPtr h, IntPtr colorscheme, float saturation, byte[] colorbuf); 

это C-код:

__declspec(dllexport) unsigned char* __cdecl heatmap_render_default_to(const heatmap_t* h, unsigned char* colorbuf) 
{ 
return heatmap_render_to(h, heatmap_cs_default, colorbuf); 
} 
__declspec(dllexport) unsigned char* heatmap_render_to(const heatmap_t* h, const heatmap_colorscheme_t* colorscheme, unsigned char* colorbuf) 
{ 
return heatmap_render_saturated_to(h, colorscheme, h->max > 0.0f ? h->max : 1.0f, colorbuf); 
} 
__declspec(dllexport) unsigned char* __cdecl heatmap_render_saturated_to(const heatmap_t* h, const heatmap_colorscheme_t* colorscheme, float saturation, unsigned char* colorbuf) 
{ 
unsigned y; 
assert(saturation > 0.0f); 
/* For convenience, if no buffer is given, malloc a new one. */ 
if (!colorbuf) { 
    colorbuf = (unsigned char*)malloc(h->w*h->h * 4); 
    if (!colorbuf) { 
     return 0; 
    } 
} 

/* TODO: could actually even flatten this loop before parallelizing it. */ 
/* I.e., to go i = 0 ; i < h*w since I don't have any padding! (yet?) */ 
for (y = 0; y < h->h; ++y) { 
    float* bufline = h->buf + y*h->w; 
    unsigned char* colorline = colorbuf + 4 * y*h->w; 

    unsigned x; 
    for (x = 0; x < h->w; ++x, ++bufline) { 
     /* Saturate the heat value to the given saturation, and then 
     * normalize by that. 
     */ 
     const float val = (*bufline > saturation ? saturation : *bufline)/saturation; 

     /* We add 0.5 in order to do real rounding, not just dropping the 
     * decimal part. That way we are certain the highest value in the 
     * colorscheme is actually used. 
     */ 
     const size_t idx = (size_t)((float)(colorscheme->ncolors - 1)*val + 0.5f); 

     /* This is probably caused by a negative entry in the stamp! */ 
     assert(val >= 0.0f); 

     /* This should never happen. It is likely a bug in this library. */ 
     assert(idx < colorscheme->ncolors); 

     /* Just copy over the color from the colorscheme. */ 
     memcpy(colorline, colorscheme->colors + idx * 4, 4); 
     colorline += 4; 
    } 
} 

return colorbuf; 

}

+2

'unsigned char *'! = 'String' –

+1

Это странно. вы выделяете память для изображения (colorbuf param), но вы говорите, что код c mallocs. Что он? А как насчет hmptr? Показывать объявление pinvoke и весь вызывающий код – pm100

+1

Функция [не выделяет память] (https://github.com/lucasb-eyer/heatmap/blob/99b8fa0670463e5c619c514a4805989d3c3af75e/heatmap.c#L189), если 'colorbuf' doesn 'оценивать значение false. Если вы просто передаете 'IntPtr.Zero', он должен выделить буфер ** для ** вас и вернуть указатель на него. – cubrr

ответ

1

Похоже heatmap_render_default_to хочет блок байтов, чтобы написать свой вывод. Эти байты должны быть либо выделены в нативной куче (например, через Marshal.AllocHGlobal), либо закреплены GC, чтобы они не двигались во время вызова функции C.

Пример:

var colourbuf = new byte[width * height * 4]; 
fixed (byte* colourbufPtr = colourbuf) 
    heatmap_render_default_to(hmPtr, colourbufPtr); 
// Now you can play with the bytes in colourbuf 

Или, если P/Invoke объявляет функцию принять byte[] ГХ пиннинга должно быть сделано для вас во время маршалинге вызова. Так просто:

var colourbuf = new byte[width * height * 4]; 
heatmap_render_default_to(hmPtr, colourbuf); 

Причина, по которой вы получили сообщение о нарушении прав доступа является то, что вы проходили в нативных байтов ANSI, которые соответствуют строке длины 0 (так, буфер, содержащий один нулевой байт) к функции который ожидает большой байтовый буфер (и, таким образом, написал его до конца).

Кроме того, убедитесь, что параметры вашего вызова и параметры маршалинга (особенно для строк) установлены правильно при импорте P/Invoke.

В общем, если вам нужно работать с API-интерфейсом C для более чем тривиального количества вызовов, я считаю, что гораздо проще спуститься в C++/CLI и написать сборку с обложкой с манифестами, а затем использовать это из C# как управляемая сборка.

+0

Я пробовал этот Кэмерон, и теперь я получаю поврежденное исключение сегментации памяти! –