2016-05-04 18 views
2

Ich bin neu mit MFC und versuche, es mit einem Projekt von MFC-Dialogbasis auf VS2008 zu lernen. Hier sind die Archivierungen, die ich gemacht habe:[MFC/C++] CBitmap-Bits über Socket senden und auf Empfängerseite neu erstellen

Zuerst habe ich es geschafft, eine Liste von Bildern von einem Ordner zu einem Listbox Control anzuzeigen. Danach behandelte ich das Click-Ereignis in jeder Zeile der Listbox, um das Bild auf der rechten Seite in Picture Control (Typ Bitmap) zu laden und anzuzeigen. Sie können das Bild unten für ein einfaches Verständnis sehen: Please click here for the image of my MFC dialog

Hier ist der Code. Hinweis m_ListCtrl und static_picture sind Variablen der Listbox und die Bildsteuerung:

void CMyClientDlg::OnLbnSelchangeList1(){ 

CString imagePath; 
m_ListCtrl.GetText(m_ListCtrl.GetCurSel(),imagePath); 

CImage picture; 
picture.Load(imagePath); 

if (!picture.IsNull()) 
{ 
    float screenWidth = 200, screenHeight = 200; 
    float imageWidth = picture.GetWidth(); 
    float imageHeight = picture.GetHeight(); 

    //scaling: 
    float pictureRatio = imageWidth/ imageHeight; 
    float newImageWidth; 
    float newImageHeight; 
    int aligmentX = 0; 
    int aligmentY = 0; 
    if (pictureRatio <= 1) 
    { 
     newImageWidth = imageWidth*(screenHeight/imageHeight); 
     newImageHeight = screenHeight; 
     aligmentX = (screenWidth-newImageWidth)/2; 
    } 
    else 
    { 
     newImageWidth = screenWidth; 
     newImageHeight = imageHeight*(screenWidth/imageWidth); 
     aligmentY = (screenHeight - newImageHeight)/2; 
    } 
    //end scaling. 
    CDC *screenDC = GetDC(); 
    CDC mDC; 
    mDC.CreateCompatibleDC(screenDC); 

    CBitmap bitMap; 
    bitMap.CreateCompatibleBitmap(screenDC, screenWidth, screenHeight); 
    CBitmap *pob = mDC.SelectObject(&bitMap); 
    mDC.SetStretchBltMode(HALFTONE); 
    picture.StretchBlt(mDC.m_hDC, aligmentX, aligmentY, newImageWidth, newImageHeight, 0, 0, imageWidth, imageHeight, SRCCOPY); 
    mDC.SelectObject(pob); 

    /*.......code to convert bitmap to BYTE* ........*/ 
    /*.......code to send BYTE* over socket........*/  

    //display the bit map 
    static_picture.SetBitmap((HBITMAP)bitMap.Detach()); 

    //clean up 
    ReleaseDC(screenDC); 
} 

}

So, jetzt möchte ich einen weiteren Schritt voran mögen, und versucht, mit Steckdose zu arbeiten ... und ja, ich erfolgreich gesendet und empfangen einfaches char * oder CString über Socket.
Was ich tun möchte ist: anstatt das Bild in diesem Dialog zu zeigen, zeigt es das Bild auf dem anderen Dialog (Server).
Irgendwie habe ich gelernt, dass es 2 Funktionen gibt, die Klangarbeit: SetBitmapBits() und GetBitmapBits() (ich ehrlich gesagt nur lesen Sie auf einige Quelle und haben keine idead, wenn sie für mein Ziel hier geeignet).

So fügte ich dieses Stück Code, das oben Bitmap in Byte-Array zu drehen bmpBuffer:

BITMAP bmpProperties; 
bitMap.GetBitmap(&bmpProperties); 
int bmpDemension = bmpProperties.bmWidthBytes*bmpProperties.bmHeight; 
BYTE* bmpBuffer=(BYTE*)GlobalAlloc(GPTR, bmpDemension); 
bitMap.GetBitmapBits(bmpDemension,bmpBuffer); 

dann diese Anordnung über Socket senden:

UpdateData(TRUE); 
char *socketBuffer = reinterpret_cast<char*>(bmpBuffer); 
send(m_ClientSocket, socketBuffer, sizeof(socketBuffer), 0); 
//clean up after send 
GlobalFree((HGLOBAL)bmpBuffer); 

Auf dem anderen Dialog. Anmerkung: Ich fest einprogrammiert haben die demension der Bitmap zu 160000, nur um das Problem zu vereinfachen:

void CMyServer2Dlg::OnReceive(){  
char *socketBuffer = new char [1025]; 
int iLen; 
iLen = recv(m_sConnected, socketBuffer, 1025, NULL); 
if(iLen==SOCKET_ERROR) 
{ 
    AfxMessageBox("Could not Receive"); 
} 
else 
{ 
    BYTE* bmpBuffer = reinterpret_cast<BYTE*>(socketBuffer); 

    //re-construct the bitmap 
    CBitmap clone; 
    CDC *screenDC = GetDC(); 
    CDC mDC; 
    mDC.CreateCompatibleDC(screenDC); 

    clone.CreateCompatibleBitmap(screenDC, 200, 200); 
    clone.SetBitmapBits(160000,bmpBuffer); 

    //Picture control(type bitmap) has variable "static_picture" 
    static_picture.SetBitmap((HBITMAP)clone.Detach()); 

    UpdateData(FALSE); 
    ReleaseDC(screenDC); 
    GlobalFree((HGLOBAL)bmpBuffer); 
} 
delete socketBuffer; 

Und es funktioniert einfach nicht ... Bitte sagen Sie mir, wo es tat ich mess up? Und sorry für die lange Post .....

+0

Haben Sie ein +1 für die Erforschung von Lösungen (ja, GetBitmapBits und SetBitmapBits sind die richtigen Funktionen, denke ich). Aber was meinst du mit "funktioniert nicht"? – immibis

+0

Danke für Ihre Antwort. Auf der Empfängerseite wird nur die schwarze Farbe 200x200 angezeigt, nicht das Bild, das ich auf der Senderseite angeklickt habe. Ich habe auch versucht, die Bitmap auf der Senderseite zum Testen neu zu konstruieren und es funktioniert normal. –

+1

Korrigieren Sie mich, wenn falsch. Ihr Empfangspuffer ist 1025 und Ihre Bitmapgröße ist 160000. Ist der Puffer groß genug? –

Antwort

0

Ich denke, der wahrscheinlichste Grund ist, dass Ihr Empfänger nicht alle Daten des Bildes bekommt. Ich schlage vor, dass Sie beim Senden eine Größe der Bitmap in das Paket einfügen, damit der Empfänger die richtige Größe erhält.

Hier sind einige Beispielcodes. Seien Sie sich bewusst, dass sie nur dazu da sind, die Idee zu zeigen, Sie müssen möglicherweise etwas debuggen, um sicherzustellen, dass sie funktionieren.

Schritt 1: Packen Sie die Größe der Bitmap. Ich nehme an, hier ist die Größe weniger als 64K, also wird ein Int verwendet. Wenn die Größe möglicherweise größer als 64 KB ist, sollten Sie INT64 verwenden.

int bmpDemension = bmpProperties.bmWidthBytes*bmpProperties.bmHeight; 
int bufferSize = bmpDemension + sizeof(int); 
BYTE* bmpBuffer=(BYTE*)GlobalAlloc(GPTR, bufferSize); 
bitMap.GetBitmapBits(bmpDemension,bmpBuffer + sizeof(int)); 
memcpy(bmpBuffer, &bmpDemension, sizeof(int)); // put the size into the head of package. 

Schritt 2: es Senden Sie Beachten Sie, verwende ich buffer hier, weil sizeof (bmpBuffer) die Zeigergröße gibt, die 4 ist, nicht die Raumgröße.

UpdateData(TRUE); 
char *socketBuffer = reinterpret_cast<char*>(bmpBuffer); 
send(m_ClientSocket, socketBuffer, bufferSize , 0); 
//clean up after send 
GlobalFree((HGLOBAL)bmpBuffer); 

Auf der Empfängerseite: Zuerst lesen Sie die Größe der Bitmap, dann auf die Größe der Daten entsprechend erhalten haben.

void CMyServer2Dlg::OnReceive(){  
char socketBuffer[1025]; 
int iLen; 
iLen = recv(m_sConnected, socketBuffer, sizeof(int), NULL); //read the bigmap size 
if(iLen==SOCKET_ERROR) 
{ 
AfxMessageBox("Could not Receive"); 
} 
else 
{ 
int dimension = *((int *) socketBuffer); 
char * bitmapBuffer = new char[dimension]; 
int readSize = dimension; 
char * pBuffer = bitmapBuffer; 
while (readSize > 0) 
{ 
    int sizeToRead = readSize > sizeof(socketBuffer) ? sizeof(socketBuffer) : readSize; 
    iLen = recv(m_sConnected, socketBuffer, sizeToRead , NULL); 
    memcpy(pBuffer, socketBuffer, iLen); 
    pBuffer += iLen; 
    readSize -= iLen; 
} 
// when the loop done, you shall have all data in bitmapBuffer. 
....  
// I leave the remaining code to you. 

Noch einmal, dieser Code dient nur dazu, die Idee zu demontieren.

+0

Vielen Dank für Ihre Hilfe! Ich werde deinen Vorschlag versuchen und dir sagen, was rauskommt. –

+0

Es funktioniert! Du bist toll. Allerdings müssen wir den socketBuffer nach jedem Zeichnen des Bildes löschen, da der Client auf ein anderes Bild klicken und einen Absturz verursachen kann. Wie auch immer, vielen Dank für Ihre Hilfe, ich kann nicht glauben, dass ich etwas so grundlegende wie Größe des Zeigers am Anfang verpasst ... Gut zu lernen. –

+0

Yeah, du hast Recht mit der Aufräumaktion. Einfach zu vergessen. Sie sind willkommen BTW: D –