使用 ffi 发送 c++ 字节数据到 flutter
Sending c++ byte data using ffi to flutter
我在 link 中使用了这段代码,使用 GdiPlus 截取屏幕并将位图转换为 png 字节。
#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;
}
问题
- 如何准备该字节数据 (std::vector data;) 以通过 dart ffi 传递它以在其中使用它颤抖?
- 请尽可能接受。
我最大的困惑是 ffi 没有相应的字节数据类型,所以我应该怎么办?
您在 Dart 端查找的数据类型是 Pointer<Uint8>
,它是指向无符号字节的指针。您可以将此指针传递到 ffi 边界并访问任一侧的指针字节。但是,在分配一些存储空间之前,指针对您没有好处(想想 malloc
/ free
)。
有两种方法可以分配指针将引用的存储空间(字节数组)。您可以 malloc
(随后 free
)C 端的字节,或者 malloc.allocate<Uint8>()
(随后 malloc.free()
)它们在 Dart 端。
然后,在 C 端,您的代码段中已经有用于将 std::vector<BYTE>
复制到指针缓冲区的示例代码:
memcpy(&data[0], the_pointer, bufsize);
从data
复制bufsize
个字节到指针指向的缓冲区。 (或者,只要您知道数据不会超出范围,您就可以将 &data[0]
分配给指针 - 并在使用后释放它)。
在 Dart 端获得 Pointer<Uint8>
后,只需调用 asTypedList
即可获得允许您访问 Dart 端字节的 Uint8List
。
此外,请记住 Dart FFI 是一个 C
接口,因此如果您想使用 C++ 类,您需要将它们包装在 C 方法中。请参阅: 那些 C 方法 can/should 只要标记为 extern "C"
.
就在 C++ 源文件中
我在 link 中使用了这段代码,使用 GdiPlus 截取屏幕并将位图转换为 png 字节。
#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;
}
问题
- 如何准备该字节数据 (std::vector data;) 以通过 dart ffi 传递它以在其中使用它颤抖?
- 请尽可能接受。
我最大的困惑是 ffi 没有相应的字节数据类型,所以我应该怎么办?
您在 Dart 端查找的数据类型是 Pointer<Uint8>
,它是指向无符号字节的指针。您可以将此指针传递到 ffi 边界并访问任一侧的指针字节。但是,在分配一些存储空间之前,指针对您没有好处(想想 malloc
/ free
)。
有两种方法可以分配指针将引用的存储空间(字节数组)。您可以 malloc
(随后 free
)C 端的字节,或者 malloc.allocate<Uint8>()
(随后 malloc.free()
)它们在 Dart 端。
然后,在 C 端,您的代码段中已经有用于将 std::vector<BYTE>
复制到指针缓冲区的示例代码:
memcpy(&data[0], the_pointer, bufsize);
从data
复制bufsize
个字节到指针指向的缓冲区。 (或者,只要您知道数据不会超出范围,您就可以将 &data[0]
分配给指针 - 并在使用后释放它)。
在 Dart 端获得 Pointer<Uint8>
后,只需调用 asTypedList
即可获得允许您访问 Dart 端字节的 Uint8List
。
此外,请记住 Dart FFI 是一个 C
接口,因此如果您想使用 C++ 类,您需要将它们包装在 C 方法中。请参阅:extern "C"
.