BitBlt конвертировать в байтовый массив и анализировать с c ++ на c #

Я пытаюсь создать DLL захвата экрана в C ++ и отправить полученные байтовые массивы в C #.

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

Вот код C ++ (составленный из битов, которые я нашел в интернете)

    __declspec(dllexport) int ScreenCap(BYTE* *data, DWORD *size)
{
try
{
//BITMAP bmpScreen;
HWND DesktopHwnd = GetDesktopWindow();
RECT DesktopParams;
HDC DevC = GetDC(DesktopHwnd);
GetWindowRect(DesktopHwnd,&DesktopParams);
DWORD Width = DesktopParams.right - DesktopParams.left;
DWORD Height = DesktopParams.bottom - DesktopParams.top;

DWORD FileSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+(sizeof(RGBTRIPLE)+1*(Width*Height*4));
*size = FileSize;
char *BmpFileData = (char*)GlobalAlloc(0x0040,FileSize);

PBITMAPFILEHEADER BFileHeader = (PBITMAPFILEHEADER)BmpFileData;
PBITMAPINFOHEADER  BInfoHeader = (PBITMAPINFOHEADER)&BmpFileData[sizeof(BITMAPFILEHEADER)];

BFileHeader->bfType = 0x4D42; // BM
BFileHeader->bfSize = sizeof(BITMAPFILEHEADER);
BFileHeader->bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);

BInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
BInfoHeader->biPlanes = 1;
BInfoHeader->biBitCount = 24;
BInfoHeader->biCompression = BI_RGB;
BInfoHeader->biHeight = Height;
BInfoHeader->biWidth = Width;

RGBTRIPLE *Image = (RGBTRIPLE*)&BmpFileData[sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)];
RGBTRIPLE color;

HDC CaptureDC = CreateCompatibleDC(DevC);
HBITMAP CaptureBitmap = CreateCompatibleBitmap(DevC,Width,Height);
SelectObject(CaptureDC,CaptureBitmap);
BOOL bRet = BitBlt(CaptureDC,0,0,Width,Height,DevC,0,0,SRCCOPY|CAPTUREBLT);
//GetDIBits(CaptureDC,CaptureBitmap,0,Height,Image,(LPBITMAPINFO)BInfoHeader, DIB_RGB_COLORS);
//GetObject(CaptureBitmap,sizeof(BITMAPFILEHEADER),&bmpScreen);
//BYTE* lpPixels = new BYTE[sizeof((LPBITMAPINFO)BInfoHeader)];
GetDIBits(CaptureDC, CaptureBitmap, 0, Height, *data, (LPBITMAPINFO)BInfoHeader, DIB_RGB_COLORS);
//DWORD Junk;
//DIBSECTION dib;
//GetObject(CaptureBitmap, sizeof(dib), (LPVOID)&dib);

//HANDLE FH = CreateFileA(BmpName,GENERIC_WRITE,FILE_SHARE_WRITE,0,CREATE_ALWAYS,0,0);
//WriteFile(FH,BmpFileData,FileSize,&Junk,0);
//CloseHandle(FH);
GlobalFree(BmpFileData);return 1;
}
catch(char *p)
{
return 0;
}
}

А вот код C #, который я использую с ключевым словом «ref».

        [DllImport("consoleapplication1.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int ScreenCap(ref byte[] data, ref int size);

public static void CapScreen()
{
try
{
int hr = 0;
byte[] gData = null;
int gSize = 0;
hr = ScreenCap(ref gData, ref gSize);
int a = 1;
}
catch(Exception ex)
{
int a = 1;
}

Я думаю, что может быть проблема с моими GetDIBits, но я не уверен. Я надеюсь, что некоторые из вас, гуру, могут направить меня на правильный путь. Благодарю.

* РЕДАКТИРОВАТЬ *

ОК Большое спасибо jdweng и filip за то, что они указали мне правильное направление. Теперь я получаю экран как IntPtr и могу отобразить его в моем приложении на C #. вот код, который сейчас работает (вроде я объясню внизу)

__declspec(dllexport) char* ScreenCap(DWORD * size)

{
пытаться
{
// Получить размеры экрана
int nScreenWidth = GetSystemMetrics (SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics (SM_CYSCREEN);

    *size = ((((24 * nScreenWidth + 31)&(~31)) / 8)*nScreenHeight);

BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);

// Create compatible DC, create a compatible bitmap and copy the screen using BitBlt()
HDC hdcScreen = GetDC(GetDesktopWindow());
HDC hdcCompatible  = CreateCompatibleDC(hdcScreen);
HBITMAP hBmp = CreateCompatibleBitmap(hdcScreen, nScreenWidth, nScreenHeight);
//HGDIOBJ hOldBmp = SelectObject(hdcCompatible, hBmp);
HGDIOBJ hOldBmp = (HGDIOBJ) SelectObject(hdcCompatible, hBmp);

BOOL bOK = BitBlt(hdcCompatible,0,0,nScreenWidth, nScreenHeight, hdcScreen,0,0,SRCCOPY|CAPTUREBLT);

SelectObject(hdcCompatible, hOldBmp); // always select the previously selected object once done
// Get the BITMAPINFO structure from the bitmap
GetDIBits(hdcScreen, hBmp, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS);

// create the bitmap buffer
char* lpPixels = new char[MyBMInfo.bmiHeader.biSizeImage];

MyBMInfo.bmiHeader.biCompression = BI_RGB;
MyBMInfo.bmiHeader.biBitCount = 24;

// get the actual bitmap buffer
GetDIBits(hdcScreen, hBmp, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS);

//Clean Up
DeleteDC(hdcCompatible);
ReleaseDC(GetDesktopWindow(), hdcScreen);
DeleteDC(hdcScreen);
DeleteObject(hBmp);
//DeleteObject(hOldBmp);

return lpPixels;
}
catch(char *p)
{
return 0;
}

}

и C #

        [DllImport("consoleapplication1.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ScreenCap(ref int size);
while(true)
{
int size = 0;
IntPtr ptr = ScreenCap(ref size);
byte[] result = new byte[size];
Marshal.Copy(ptr, result, 0, size);
Marshal.Release(ptr);
ptr = IntPtr.Zero;
MainWindow.Dispatcher.Invoke(new Action(
() =>
{
System.Windows.Media.ImageSource ThumbnailImage = System.Windows.Media.Imaging.BitmapSource.Create(1920, 1080, 96, 96, System.Windows.Media.PixelFormats.Bgr24, null, result, 1920 * 3);
MainWindow.canvasMain.Background = new System.Windows.Media.ImageBrush(ThumbnailImage);
result = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
), null);
}

Не уверен, что проблема, с которой я сейчас сталкиваюсь, связана с этим, но сейчас я получаю серьезную утечку памяти из C ++ dll. Если это еще одна проблема, нужно ли мне создавать новую тему?

** Редактировать **

Проблема решена путем создания новой функции в dll C ++ для удаления возвращенного массива char. не может быть элегантным, но это работает.

Я хотел бы поблагодарить Филиппа, комментарии которого помогли мне заглянуть во все виды мест и увидеть другие вещи. Jdweng, ваш IntPtr был посланным богом. Не уверен, как я установил это, как ответил Jdweng. хотел бы наградить вас обоих.

-2

Решение

Вот что сработало для меня, если кто-то ищет то же самое. Я хотел бы выразить огромную благодарность Филипу Коцице и jdweng, чьи предложения дали мне некоторые идеи и очень помогли. Спасибо и высоко ценим.

C ++

    char* lpPixels;
__declspec(dllexport) BOOL ScreenCapClean()
{
delete[] lpPixels;
return 1;
}

__declspec(dllexport) char* ScreenCap(DWORD * size)
{
try
{
// Get screen dimensions
int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);

*size = ((((24 * nScreenWidth + 31)&(~31)) / 8)*nScreenHeight);

BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
MyBMInfo.bmiHeader.biWidth = nScreenWidth;
MyBMInfo.bmiHeader.biHeight = -nScreenHeight;
MyBMInfo.bmiHeader.biPlanes = 1;
MyBMInfo.bmiHeader.biBitCount = 24;
MyBMInfo.bmiHeader.biCompression = BI_RGB;
MyBMInfo.bmiHeader.biSizeImage = 0;
MyBMInfo.bmiHeader.biXPelsPerMeter = 0;
MyBMInfo.bmiHeader.biYPelsPerMeter = 0;
MyBMInfo.bmiHeader.biClrUsed = 0;
MyBMInfo.bmiHeader.biClrImportant = 0;

// Create compatible DC, create a compatible bitmap and copy the screen using BitBlt()
HDC hdcScreen = GetDC(0);
HDC hdcCompatible  = CreateCompatibleDC(hdcScreen);
HBITMAP hBmp = CreateCompatibleBitmap(hdcScreen, nScreenWidth, nScreenHeight);
HGDIOBJ hOldBmp = (HGDIOBJ) SelectObject(hdcCompatible, hBmp);

BOOL bOK = BitBlt(hdcCompatible,0,0,nScreenWidth, nScreenHeight, hdcScreen,0,0,SRCCOPY|CAPTUREBLT);

SelectObject(hdcCompatible, hOldBmp); // always select the previously selected object once done
// Get the BITMAPINFO structure from the bitmap
GetDIBits(hdcScreen, hBmp, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS);

// create the bitmap buffer
lpPixels = new char[MyBMInfo.bmiHeader.biSizeImage];

MyBMInfo.bmiHeader.biCompression = BI_RGB;
MyBMInfo.bmiHeader.biBitCount = 24;

// get the actual bitmap buffer
GetDIBits(hdcScreen, hBmp, 0, -MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS);

//Clean Up
ReleaseDC(0, hdcScreen);
ReleaseDC(0, hdcCompatible);
DeleteDC(hdcCompatible);
DeleteDC(hdcScreen);
DeleteObject(hBmp);
DeleteObject(hOldBmp);

return lpPixels;
}
catch(char *p)
{
return 0;
}
}

C #

    [DllImport("consoleapplication1.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ScreenCap(ref int size);
[DllImport("consoleapplication1.dll", CallingConvention = CallingConvention.Cdecl)]
static extern bool ScreenCapClean();

int size = 0;
IntPtr ptr = ScreenCap(ref size);
byte[] result = new byte[size];
Marshal.Copy(ptr, result, 0, size);
Marshal.Release(ptr);
ptr = IntPtr.Zero;
//After doing what's required with the byte array
bool hr = ScreenCapClean();
0

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector