Я программирую некоторые графические фильтры в моей основной программе, основанной на C #.
Однако C # не быстр для getpixel / putpixel.
Я видел обходные пути для этого, используя небезопасный код в C #
Небезопасный код также вызывает у меня чувство небезопасности, поскольку я понимаю преимущества безопасного кода и очистки памяти.
Так что теперь мне интересно ….
Может быть, лучше написать этот небезопасный код в отдельной библиотеке на основе C ++?
Однако я никогда не делал смешанные языковые программы, поэтому мне интересно.
И что, если бы я использовал другой компилятор для написания c ++ 11 .dll, это было бы проблемой?
Основная программа написана в Visual Studio 2010 Expres
Если вы используете C ++, вы также можете использовать C # с небезопасным кодом. И то, и другое небезопасно, и в C # вам все равно не нужно заботиться об очистке памяти. Единственное, о чем вам нужно заботиться, это доступ к недействительным указателям, что приведет к AccessViolationException
,
public unsafe void SwapChannels(Byte[] imageSrc)
{
fixed (Byte* pImageSrc = imageSrc)
{
// Swap channels here
}
}
Я использую небезопасный код в моих библиотеках изображений тоже. Если вы не планируете кроссплатформенность, вы также можете использовать C ++ / CLI.
На самом деле я делаю то же самое, что вы упомянули (графические фильтры), используя CUDA. Чтобы иметь возможность вызывать функции C из управляемого кода (WinForms), я использую InteropServices.
Допустим, у вас есть 2 проекта в решении — библиотека C ++ и несколько проектов C #.
Для объявления функции в библиотеке C ++ я использую следующие параметры:
extern "C" int __declspec(dllexport) __stdcall cudaCopyInputData
(int n, int w, int h, byte* data)
{
inputBuffer = data;
bufferLength = n;
inputWidth = w;
inputHeight = h;
useFloatBuffer = 0;
binaryBufferValid = 0;
int bufferSize = bufferLength * sizeof(byte);
int floatBufferSize = bufferLength * sizeof(float);
int binaryBufferSize = w * h * sizeof(int);
cudaMalloc((void**)&cudaInputBuffer, bufferSize);
cudaMemcpy(cudaInputBuffer, inputBuffer, bufferSize, cudaMemcpyHostToDevice);
cudaMalloc((void**)&cudaFloatBuffer, floatBufferSize);
cudaMalloc((void**)&cudaBinaryBuffer, binaryBufferSize);
return 0;
}
Чтобы использовать его из проекта C #, я импортирую эту функцию как статический метод с использованием InteropServices:
[DllImport("CUDA Dll.dll", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern int cudaCopyInputData(int n, int w, int h, IntPtr data);
Затем вы можете использовать его из управляемого кода в качестве стандартного метода.
Чтобы передать растровые данные импортированному методу, вы можете использовать что-то вроде этого:
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
Затем передайте bmpData.Scan0 как указатель на растровые данные и некоторые другие параметры, такие как Width, Height, Stride или любой другой, который вы хотите выяснить в формате данных в функции C. В приведенном выше примере у вас будет 4 байта на каждый пиксель (3 байта + 1 фиктивный байт), поэтому его удобно обрабатывать.
Чтобы повторно использовать обработанные данные из вашего объекта BMP, вы просто вызываете его после обработки:
bmp.UnlockBits(bmpData);
Существует несколько способов взаимодействия между C ++ и C #: C ++ / CLI, COM и P / Invoke.
В C ++ / CLI и COM есть области, в которых любой из них может быть лучше, но я не думаю, что P / Invoke следует когда-либо использовать, за исключением некоторых быстрых и грязных решений.
В вашем случае, особенно если учесть, что C ++ DLL создается с другим компилятором, я думаю, что COM — ваш лучший выбор.
Но обратите внимание, что использование C ++ во многом похоже на использование небезопасного кода в C #. Например, указатели повсюду.
SWIG позволяет легко переносить код C ++ и выставлять классы / функции в c #. Я использовал его, чтобы показать некоторые из моих процедур обработки изображений в c #, и это очень просто. В итоге вы получаете классы, ведущие себя как классы c #, сгенерированные SWIG обертки обрабатывают преобразования типов (в основном) и P / Invoke.
Сайт swig.org недоступен, в данный момент я пишу, если кто-то знает почему, пожалуйста, прокомментируйте
Что касается смешения компиляторов, у меня есть хороший опыт работы со скомпилированной Mingw DLL.
редактировать: вы все еще можете получить доступ к страница проекта sourceforge