2010-08-22 3 views
3

Я начал работать над чем-то похожим на приложение удаленного управления в C++. Я хочу перенести скриншот конкретного окна на другой компьютер и отобразить его в окне. Обе функции GetDIBits и SetDIBits преуспевают, соединение установлено, данные отправляются, но изображение не появляется с другой стороны, только чернота.Передача растровых изображений с использованием Winsock, GetDIBits и SetDiBits

Вот мой отправка код:

void GetScreenData(BITMAPINFO* bi, BYTE* buf) //gets the bitmap data 
{ 
    HBITMAP hBitmap; 
    BITMAP Bitmap; 
    RECT r; 

    HDC ActiveDC = GetDC(hActive); 
    HDC CopyDC = CreateCompatibleDC(ActiveDC); 

    GetWindowRect(hActive, &r); 

    int scrWidth = r.right-r.left; 
    int scrHeight = r.bottom-r.top; 

    hBitmap = CreateCompatibleBitmap(ActiveDC, scrWidth, scrHeight); 
    SelectObject(CopyDC, hBitmap); 

    BitBlt(CopyDC, 0, 0, scrWidth, scrHeight, ActiveDC, 0, 0, SRCCOPY); 

    GetObject(hBitmap, sizeof(BITMAP), &Bitmap); 

    int cClrBits = Bitmap.bmPlanes*Bitmap.bmBitsPixel; 

    memset(bi, 0, sizeof(BITMAPINFO)); 

    bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
    bi->bmiHeader.biWidth = Bitmap.bmWidth; 
    bi->bmiHeader.biHeight = Bitmap.bmHeight; 
    bi->bmiHeader.biPlanes = Bitmap.bmPlanes; 
    bi->bmiHeader.biBitCount = Bitmap.bmBitsPixel; 

    if(cClrBits<24) 
    { 
    bi->bmiHeader.biClrUsed = (1<<cClrBits); 
    } 

    bi->bmiHeader.biCompression = BI_RGB; 
    bi->bmiHeader.biSizeImage = ((bi->bmiHeader.biWidth * cClrBits +31) & ~31)/8*bi->bmiHeader.biHeight; 

    int i = GetDIBits(CopyDC, hBitmap, 0, scrHeight, buf, bi, DIB_RGB_COLORS); 

    printf("GetDIBits returned %i\n", i); 

    ReleaseDC(hActive, ActiveDC); 
    DeleteDC(CopyDC); 
} 

DWORD WINAPI SendImage(LPVOID param) //sends the bitmap data 
{ 
    BITMAPINFO bi; 
    BYTE* data = new BYTE[256*256*256]; 
    BYTE* buf = new BYTE[256*256*256]; 
    BYTE *packetsize1, *packetsize2; 
    int biSize = sizeof(BITMAPINFO); 
    int i, clocks, oldclocks=0; 

    while(true) 
    { 
    clocks=clock(); 

    if((clocks-oldclocks)*CLOCKS_PER_SEC<0.1) 
    { 
     continue; 
    } 

    oldclocks=clocks; 

    if(bConnected) 
    { 
     GetScreenData(&bi, buf); 

     i=0; 

     data[i++]=3; 
     packetsize1=&data[i++]; 
     packetsize2=&data[i++]; 

     memcpy(data+i, &bi, biSize); 

     i+=biSize; 

     memcpy(data+i, buf, bi.bmiHeader.biSizeImage); 

     printf("Sending image...\n"); 

     i+=bi.bmiHeader.biSizeImage; 

     *packetsize1=int(i/256); 
     *packetsize2=int(i%256); 

     send(s, (char*)data, i, 0); 
    } 
    } 
} 

А вот принимающая сторона:

void DrawScreen(HDC hdc) //called from windows message WM_PAINT 
{ 
    HGDIOBJ hobj; 

    hobj = SelectObject(RemoteDC, hRemoteBitmap); 

    BitBlt(hdc, 0, 0, scrWidth, scrHeight, RemoteDC, 0, 0, SRCCOPY); 

    SelectObject(hdc, hobj); 
} 

DWORD WINAPI RecvData(LPVOID param) 
{ 
    BYTE* data = new BYTE[256*256*256]; 
    int packetsize, num; 
    int newWidth, newHeight; 
    int recvimgsize=0; 

    bool bAwaitingImage = false; 

    while(true) 
    { 
    if(bConnected) 
    { 
     num=recv(s, (char*)data, 3, 0); 

     if(num>0) 
     { 
     packetsize = data[1]*256+data[2]; 

     num=recv(s, (char*)(data+3), packetsize-3, 0); 
     } 

     if(num>0) 
     { 
     switch(data[0]) 
     { 
      case 2: //received information about window size (image size) 
      newWidth = data[3]*256+data[4]; 
      newHeight = data[5]*256+data[6]; 

      if(newHeight!=scrHeight || newWidth!=scrWidth) 
      { 
       scrWidth = newWidth; 
       scrHeight = newHeight; 

       RECT r; 

       GetWindowRect(hwnd, &r); 
       SetWindowPos(hwnd, NULL, r.left, r.top, scrWidth, scrHeight, 0); 

       HDC ThisDC = GetDC(hwnd); 

       DeleteDC(RemoteDC); 
       RemoteDC = CreateCompatibleDC(ThisDC); 

       DeleteObject(hRemoteBitmap); 
       hRemoteBitmap = CreateCompatibleBitmap(ThisDC, scrWidth, scrHeight); 

       SelectObject(RemoteDC, hRemoteBitmap); 

       ReleaseDC(hwnd, ThisDC); 
      } 
      break; 
      case 3: 
      { 
      BITMAPINFO bi; 
      HBITMAP hBitmap; 

      int biSize = sizeof(BITMAPINFO); 
      memcpy(&bi, data+3, biSize); 
      SetDIBits(RemoteDC, hRemoteBitmap, 0, scrHeight, data+biSize+3, &bi, DIB_RGB_COLORS); 

      InvalidateRect(hwnd, NULL, false); 

      break; 
      } 
     } 

     continue; 
     } 

     if(num==0) 
     { 
     //connection closed 
     bConnected=false; 
     }else{ 
     //error 
     bConnected=false; 
     } 
    } 
    } 
} 

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

+1

Вы проверили свой код декодирования и отображения, не отправив его сначала по кабелю? –

+1

Только что сделал (как-то я не думал об этом раньше). Он работает так, как ожидалось. Должно быть, что-то не так с передачей ... –

+0

Хорошо, что устраняет значительную часть проблемы. Не могу обещать ничего, но я посмотрю, если что-нибудь выскакивает на меня с сетевым материалом :) –

ответ

0

Я назначил недостаточное количество байтов для хранения пакета, теперь он работает, и я увеличил это число. ;-)

0

Проблема с размещенным кодом заключается в том, что для общей длины передаваемых данных было два (0 +32) и (1 + 1) и [данные + 2]. Два байта обрабатывают до 64 тыс. Данных и изображений, что легко выходит за рамки этого, значение i не проверяется на переполнение.

Чтобы оживить фрагмент кода, нужно добавить туда биты, чтобы они могли занимать реальную длину. То есть должен быть дополнительный байт или два, чтобы сделать длину пакета 24 или 32 бита.