I used this code in this link to take a screenshot of the screen using GdiPlus and convert the bitmap to png bytes.

#include <iostream>
#include <fstream>
#include <vector>
#include <Windows.h>
#include <gdiplus.h>

bool save_png_memory(HBITMAP hbitmap, std::vector<BYTE>& data)
{
    Gdiplus::Bitmap bmp(hbitmap, nullptr);

    //write to IStream
    IStream* istream = nullptr;
    if (CreateStreamOnHGlobal(NULL, TRUE, &istream) != 0)
        return false;

    CLSID clsid_png;
    if (CLSIDFromString(L"{557cf406-1a04-11d3-9a73-0000f81ef32e}", &clsid_png)!=0)
        return false;
    Gdiplus::Status status = bmp.Save(istream, &clsid_png);
    if (status != Gdiplus::Status::Ok)
        return false;

    //get memory handle associated with istream
    HGLOBAL hg = NULL;
    if (GetHGlobalFromStream(istream, &hg) != S_OK)
        return 0;

    //copy IStream to buffer
    int bufsize = GlobalSize(hg);
    data.resize(bufsize);

    //lock & unlock memory
    LPVOID pimage = GlobalLock(hg);
    if (!pimage)
        return false;
    memcpy(&data[0], pimage, bufsize);
    GlobalUnlock(hg);

    istream->Release();
    return true;
}

int main()
{
    CoInitialize(NULL);

    ULONG_PTR token;
    Gdiplus::GdiplusStartupInput tmp;
    Gdiplus::GdiplusStartup(&token, &tmp, NULL);

    //take screenshot
    RECT rc;
    GetClientRect(GetDesktopWindow(), &rc);
    auto hdc = GetDC(0);
    auto memdc = CreateCompatibleDC(hdc);
    auto hbitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
    auto oldbmp = SelectObject(memdc, hbitmap);
    BitBlt(memdc, 0, 0, rc.right, rc.bottom, hdc, 0, 0, SRCCOPY);
    SelectObject(memdc, oldbmp);
    DeleteDC(memdc);
    ReleaseDC(0, hdc);

    //save as png
    std::vector<BYTE> data;
    if(save_png_memory(hbitmap, data))
    {
        //write from memory to file for testing:
        std::ofstream fout("test.png", std::ios::binary);
        fout.write((char*)data.data(), data.size());
    }
    DeleteObject(hbitmap);

    Gdiplus::GdiplusShutdown(token);
    CoUninitialize();

    return 0;
}

Question

  • How can prepare that byte data (std::vector data;) to pass it through dart ffi to work with it in flutter?
  • Please anyway possible will be accepted.

My biggest confussion is ffi doesn't have a coresponding byte data type, so how should I go by it?


Solution 1: Richard Heap

The data type you are looking for on the Dart side is Pointer<Uint8>, which is a pointer to unsigned bytes. You can pass this pointer over the ffi boundary and access the pointee bytes on either side. But, pointer is no good to you until you allocate some storage (think malloc / free).

There are two ways to allocate the storage (array of bytes) that the pointer will reference. You can either malloc (and subsequently free) the bytes on the C side, or malloc.allocate<Uint8>() (and subsequently malloc.free()) them on the Dart side.

Then, on the C side you already have sample code in your snippet for copying the std::vector<BYTE> into the pointee buffer:

memcpy(&data[0], the_pointer, bufsize);

copies bufsize bytes from data to the buffer pointed to by the pointer. (Alternatively, you could just assign &data[0] to the pointer as long as you know data won't go out of scope - and you free it after you use it).

Once you have the Pointer<Uint8> on the Dart side, just call asTypedList to get a Uint8List that allows you to access the bytes on the Dart side.

Also, remember that Dart FFI is a C interface, so if you want to use C++ classes you will need to wrap them in C methods. See: Can I call a C++ constructor function in dart ffi? Those C methods can/should be in C++ source files as long as they are marked extern "C".