-3

So I have a working HBITMAP which can be set to the clipboard using SetClipboardData. What I'm trying to do is send the HBITMAP to another application (without writing anything to disk) which will receive it and be able set it to the clipboard just as the original application could do. I know that you can't just send the handle so I used GetObject and GetDIBits and sent the collected data across. I've looked at all the other people's stackoverflow questions about sending hbitmaps over a network but none of the answers given have worked for me.

UPDATE: Code still not working after updated.

This is now what it shows as when I paste the clipboard into mspaint

Here's what my code looks like now:

Client:

#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>

#pragma comment(lib, "Ws2_32.lib")
#define Port 6000

SOCKET Socket, Sub;
WSADATA Winsock;
sockaddr_in Addr;
sockaddr_in IncomingAddress;
int AddressLen = sizeof(IncomingAddress);

BOOL send_function(BYTE* dib, int dib_size) {

    WSAStartup(MAKEWORD(2, 2), &Winsock);    // Start Winsock

    if (LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2)    // Check version
    {
        WSACleanup();
        return 0;
    }

    Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    ZeroMemory(&Addr, sizeof(Addr));
    Addr.sin_family = AF_INET;
    Addr.sin_port = htons(Port);
    bind(Socket, (sockaddr*)&Addr, sizeof(Addr));

    if (listen(Socket, 1) == SOCKET_ERROR)
    {
        printf("listening error\n");
    }
    else
    {
        printf("listening ok\n");
    }

    if (Sub = accept(Socket, (sockaddr*)&IncomingAddress, &AddressLen))
    {
        char* ClientIP = inet_ntoa(IncomingAddress.sin_addr);
        int ClientPort = ntohs(IncomingAddress.sin_port);
        printf("Client conncted!\n");
        printf("IP: %s:%d\n", ClientIP, ClientPort);

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

        char bufsize[10];
        sprintf(bufsize, "%d", dib_size);

        send(Sub, (char*)bufsize, 10, 0);
        send(Sub, (char*)dib, dib_size, 0);


        closesocket(Sub);
        closesocket(Socket);
        WSACleanup();
    }
}


int main()
{
    HWND hwnd = GetWindow(GetForegroundWindow(), GW_HWNDLAST);
    RECT rc;
    GetWindowRect(hwnd, &rc);
    HDC hdcScreen = GetDC(NULL);
    HDC hdc = CreateCompatibleDC(hdcScreen);
    HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen,
        rc.right - rc.left, rc.bottom - rc.top);
    SelectObject(hdc, hbmp);
    //Print to memory hdc
    PrintWindow(hwnd, hdc, NULL);



    auto hcopy = (HBITMAP)CopyImage(hbmp, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);

    BITMAP bm;
    GetObject(hcopy, sizeof(bm), &bm);

    BITMAPINFOHEADER bi = { sizeof(bi) };
    bi.biWidth = bm.bmWidth;
    bi.biHeight = bm.bmHeight;
    bi.biBitCount = bm.bmBitsPixel;
    bi.biPlanes = bm.bmPlanes;
    bi.biSizeImage = bm.bmWidthBytes * bm.bmHeight;

    int dib_size = sizeof(bi) + bi.biSizeImage;
    BYTE* dib = new BYTE[dib_size];
    memcpy(dib, &bi, sizeof(bi));
    memcpy(dib + sizeof(bi), bm.bmBits, bi.biSizeImage);
    send_function(dib, dib_size);

    //cleanup
    DeleteObject(hcopy);
    delete[]dib;
    getchar();
    return 0;
}

Server:

#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>

#pragma comment(lib, "Ws2_32.lib")

SOCKET Socket;
WSADATA Winsock;
sockaddr_in Addr;
int Addrlen = sizeof(Addr);


void receive_function(BYTE* dib, int dib_size)
{
    BITMAPINFOHEADER* bi = (BITMAPINFOHEADER*)dib;
    BYTE* bits = dib + sizeof(bi);
    HBITMAP hbitmap = CreateBitmap(bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount, bits);
    OpenClipboard(NULL);
    EmptyClipboard();
    SetClipboardData(CF_BITMAP, hbitmap);
    CloseClipboard();
    printf("Clipboard set!");
    getchar();
}


int main()
{

    WSAStartup(MAKEWORD(2, 2), &Winsock);    // Start Winsock

    if (LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2)    // Check version
    {
        WSACleanup();
        return 0;
    }

    Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    ZeroMemory(&Addr, sizeof(Addr));    // clear the struct
    Addr.sin_family = AF_INET;    // set the address family
    Addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    Addr.sin_port = htons(6000);    // set the port

    if (connect(Socket, (sockaddr*)&Addr, sizeof(Addr)) < 0)
    {
        printf("Connection failed !\n");
        getchar();
        return 0;
    }

    printf("Connection successful !\n");

    printf("Receiving data .. \n");

    int dib_size = 0;
    char Filesize[10];

    if (recv(Socket, Filesize, 10, 0)) // File size
    {
        dib_size = atoi(Filesize);
    }
    printf("File size: %d\n", dib_size);

    BYTE* dib = new BYTE[dib_size];
    if (recv(Socket, (char*)dib, dib_size, 0))
    {
       receive_function(dib, dib_size);
    }

    getchar();
    return 0;
}

Any and all help appreciated!

  • 1
    Please show the work you've already written so far, and explain how exactly your program doesn't work or doesn't produce the expected results. You have to show your work first, before asking for help on stackoverflow.com. Noone on stackoverflow.com will write a bunch of new code in response to this type of a question. For more information, see [ask] questions, take the [tour], and read the [help]. – Sam Varshavchik Nov 23 '19 at 16:55
  • Do you know how to persist an image to a stream, or do you only need to know how to send data over a socket? Breaking the problem down helps. – David Heffernan Nov 23 '19 at 19:30
  • My problem is that the data is getting sent when I put it in another handle it leaves me with a black screen. Like I said "I could just be implementing it wrong". So to answer your question, I need to send data over a socket but I've never tried to send a bitmap over a socket before so I'm probably doing it wrong. That's why i'm looking for examples. –  Nov 23 '19 at 21:05
  • You are sending 256 bytes for dibsize (which is only 10 bytes), then you read it as 1024 bytes filesize (the buffer is still only 10 bytes), and you repeat that a second time, you shouldn't. You end up reading the dib at the wrong offset. Pick one "filesize", send it only once, and receive it only once. Don't use 10, 256, 1024... to describe the same buffer size. – Barmak Shemirani Nov 24 '19 at 18:00
  • The code which you provided works. The only drawback is that the image is reversed. – Strive Sun Nov 26 '19 at 10:04
  • The code does not work. –  Nov 26 '19 at 19:20
  • Please help check the value of `hbitmap` which located in `hbitmap = CreateBitmap(bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount, bits)`.And I will use [a GIF picture](https://i.stack.imgur.com/EtL3T.gif) to show the whole process. If there is something different from you, please let me know.I have replaced the code of the clipboard with the code stored as a file, so as to better display the transferred pictures. – Strive Sun Nov 27 '19 at 02:40
  • check the value? I don't understand. And I also made a [GIF picture](https://i.imgur.com/9Oeo1rc.gif) so you can see what happens for me. I replaced the clipboard with code to store in a file too (but the result still turns out the same). In the GIF there are 2 bitmaps that get created, 1 before sending and 1 after sending, It shows that the image is fine until sent though the socket. –  Nov 27 '19 at 21:56

2 Answers2

1

You can save a HBITMAP into memory same as stored in File..

make GDI+ Bitmap using Bitmap::FromHBITMAP().

Using CreateStreamOnHGlobal, you can create stream on memory.. and using GDI+ Bitmap::Save(), you can write a bitmap file into memory..

send it to socket..

On the other side of socket, memory to Stream and to Bitmap.

Search MSDN. You can find example...

Peter Lee
  • 136
  • 9
  • @HenryJones ..read this [link](https://stackoverflow.com/questions/51383896/c-gdibitmap-to-png-image-in-memory) – Peter Lee Nov 23 '19 at 17:16
0

Please use LoadImage to load BMP image.

Because the code you provided in your question is to get the background of the desktop, and the GIF picture you provided is a local image file loaded with api(GIF is too vague and I can't identify which API you are using).

After my test, there should be an error occurred while yoou loading the bmp image.

Modified code:

Server:

#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <gdiplus.h>

using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")

#pragma comment(lib, "Ws2_32.lib")
#pragma warning(disable: 4996)


SOCKET Socket;
WSADATA Winsock;
sockaddr_in Addr;
int Addrlen = sizeof(Addr);
HBITMAP hbitmap;



int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
    UINT  num = 0;          // number of image encoders
    UINT  size = 0;         // size of the image encoder array in bytes

    ImageCodecInfo* pImageCodecInfo = NULL;

    GetImageEncodersSize(&num, &size);
    if (size == 0)
        return -1;  // Failure

    pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    if (pImageCodecInfo == NULL)
        return -1;  // Failure

    GetImageEncoders(num, size, pImageCodecInfo);

    for (UINT j = 0; j < num; ++j)
    {
        if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
        {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return 0;  // Success
        }
    }
    free(pImageCodecInfo);
    return -1;  // Failure
}

void receive_function(BYTE* dib, int dib_size)
{
    BITMAPINFOHEADER* bi = (BITMAPINFOHEADER*)dib;
    BYTE* bits = dib + sizeof(bi);
    hbitmap = CreateBitmap(bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount, bits);


    /*OpenClipboard(NULL);
    EmptyClipboard();
    SetClipboardData(CF_BITMAP, hbitmap);
    CloseClipboard();
    printf("Clipboard set!");*/
//  getchar();
}


int main()
{
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    WSAStartup(MAKEWORD(2, 2), &Winsock);    // Start Winsock

    if (LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2)    // Check version
    {
        WSACleanup();
        return 0;
    }

    Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    ZeroMemory(&Addr, sizeof(Addr));    // clear the struct
    Addr.sin_family = AF_INET;    // set the address family
    Addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    Addr.sin_port = htons(6000);    // set the port

    if (connect(Socket, (sockaddr*)&Addr, sizeof(Addr)) < 0)
    {
        printf("Connection failed !\n");
        getchar();
        return 0;
    }

    printf("Connection successful !\n");

    printf("Receiving data .. \n");

    int dib_size = 0;
    char Filesize[10];

    if (recv(Socket, Filesize, 10, 0)) // File size
    {
        dib_size = atoi(Filesize);
    }
    printf("File size: %d\n", dib_size);

    BYTE* dib = new BYTE[dib_size];
    if (recv(Socket, (char*)dib, dib_size, 0))
    {
        receive_function(dib, dib_size);
    }
    CLSID myClsId;
    int retVal = GetEncoderClsid(L"image/bmp", &myClsId);
    Bitmap *image = new Bitmap(hbitmap, NULL);
    image->Save(L"output.bmp", &myClsId, NULL);
    delete image;

    GdiplusShutdown(gdiplusToken);

    getchar();
    return 0;
}

Updated:

With the bitmap pixels, note that the captured data has reversed order with the normal bitmap data, so we have to convert it to the correct.

Modeified client code:

#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>

#pragma comment(lib, "Ws2_32.lib")
#pragma warning(disable: 4996)
#define Port 6000

SOCKET Socket, Sub;
WSADATA Winsock;
sockaddr_in Addr;
sockaddr_in IncomingAddress;
int AddressLen = sizeof(IncomingAddress);

BOOL send_function(BYTE* dib, int dib_size) {

    WSAStartup(MAKEWORD(2, 2), &Winsock);    // Start Winsock

    if (LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2)    // Check version
    {
        WSACleanup();
        return 0;
    }

    Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    ZeroMemory(&Addr, sizeof(Addr));
    Addr.sin_family = AF_INET;
    Addr.sin_port = htons(Port);
    bind(Socket, (sockaddr*)&Addr, sizeof(Addr));

    if (listen(Socket, 1) == SOCKET_ERROR)
    {
        printf("listening error\n");
    }
    else
    {
        printf("listening ok\n");
    }

    if (Sub = accept(Socket, (sockaddr*)&IncomingAddress, &AddressLen))
    {
        char* ClientIP = inet_ntoa(IncomingAddress.sin_addr);
        int ClientPort = ntohs(IncomingAddress.sin_port);
        printf("Client conncted!\n");
        printf("IP: %s:%d\n", ClientIP, ClientPort);

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

        char bufsize[10];
        sprintf(bufsize, "%d", dib_size);

        send(Sub, (char*)bufsize, 10, 0);
        send(Sub, (char*)dib, dib_size, 0);


        closesocket(Sub);
        closesocket(Socket);
        WSACleanup();
    }
}


int main()
{       
    HBITMAP Bitmap = (HBITMAP)LoadImage(NULL,
        "C:\\Users\\strives\\Desktop\\timg.bmp",  // file containing bitmap
        IMAGE_BITMAP,  // type = bitmap
        0, 0,      // original size
        LR_LOADFROMFILE);
    auto hcopy = (HBITMAP)CopyImage(Bitmap, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);

    BITMAP bm;
    GetObject(hcopy, sizeof(bm), &bm);

    BITMAPINFOHEADER bi = { sizeof(bi) };
    bi.biWidth = bm.bmWidth;
    bi.biHeight = bm.bmHeight;
    bi.biBitCount = bm.bmBitsPixel;
    bi.biPlanes = bm.bmPlanes;
    bi.biSizeImage = bm.bmWidthBytes * bm.bmHeight;

    //convert   
    LONG lineSize = bi.biWidth * bi.biBitCount / 8;
    BYTE* pLineData = new BYTE[lineSize];
    BYTE* pStart;
    BYTE* pEnd;
    BYTE* pData = (BYTE*)bm.bmBits;
    LONG lineStart = 0;
    LONG lineEnd = bi.biHeight - 1;
    while (lineStart < lineEnd)
    {
        pStart = pData + (lineStart * lineSize);
        pEnd = pData + (lineEnd * lineSize);
        // Swap the top with the bottom
        memcpy(pLineData, pStart, lineSize);
        memcpy(pStart, pEnd, lineSize);
        memcpy(pEnd, pLineData, lineSize);
        // Adjust the line index
        lineStart++;
        lineEnd--;
    }

    int dib_size = sizeof(bi) + bi.biSizeImage;
    memcpy(pData, &bi, sizeof(bi));
    send_function(pData, dib_size);

    //cleanup
    DeleteObject(hcopy);
    delete pLineData;
    getchar();
    return 0;
}
Strive Sun
  • 5,988
  • 1
  • 9
  • 26
  • Hi, thanks for the help! Only problem though is i'm not wanting to load or save the bitmap image. I already have a Bitmap handle in memory and I want to end up with a Bitmap handle on the other side without writing anything to disk. I was just saving it in the GIF to portray what my bitmap looked like in memory. –  Nov 28 '19 at 12:45
  • @HenryJones Yeah, you can continue to enable the clipboard function as long as you can load the bmp image handle correctly. – Strive Sun Nov 29 '19 at 01:22
  • Got it, one more little problem though, the bitmap is cut off near the end of the right side and stuck on the left, see [here](https://i.imgur.com/U4aowBy.png) (I replaced the handle that the window takes a picture of to make it more obvious) –  Nov 29 '19 at 17:01
  • @HenryJones Yes, because the captured data has reversed order with the normal bitmap data, it may cause this situation. I have modified the client's code, and now the image can be displayed correctly. – Strive Sun Dec 03 '19 at 02:27