新建一个空项目
在项目路径下有个创建一个res文件夹,里面存放资源图片
让自定义资源类型,估计是因为这张图片是jpg格式的,那就自定义一个格式吧:JPG
添加了资源后,稍等片刻,rc文件和头文件会自动写入资源的信息
现在加载资源文件就好了,写个例子测试一下
#include
#include
#include
using namespace cv;
#include"resource.h"
using namespace std;
//加载资源
Mat GetMatFromResource(unsigned int idi)
{
//定位自定义资源,如果是从本模块定位资源,也可将句柄简单地置为NULL即可
HMODULE ghmodule = GetModuleHandle(NULL);
//HMODULE ghmodule = GetModuleHandle(L"#####.exe");//这里两种方式都可以
if (ghmodule == NULL)
{
cout << "ghmodule = NULL" << endl;
return Mat::zeros(0, 0, CV_8UC4);
}
//LPCTSTR PNG;
//HRSRC hrsrc = FindResource(ghmodule, MAKEINTRESOURCE(idi), L"RT_RCDATA");
HRSRC hrsrc = FindResource(ghmodule, MAKEINTRESOURCE(idi), L"JPG");
if (hrsrc == NULL)
{
cout << "hrsrc = NULL" << endl;
return Mat::zeros(255, 255, CV_8UC4);
}
HGLOBAL hg = LoadResource(ghmodule, hrsrc);
if (hg == NULL)
{
return Mat::zeros(0, 0, CV_8UC4);
}
unsigned char* addr = (unsigned char*)(LockResource(hg));
DWORD size = SizeofResource(ghmodule, hrsrc);
cout << "SizeofResource" << size << endl;
_InputArray pic_arr(addr, size);
return imdecode(pic_arr, IMREAD_UNCHANGED);
}
int main()
{
Mat marker_pic = GetMatFromResource(107);
cout << marker_pic.size() << endl;
cout << GetCurrentProcess() << endl;
cout << GetCurrentThreadId() << endl;
namedWindow("pic");
imshow("pic", marker_pic);
waitKey(0);
}
注意:
HMODULE ghmodule = GetModuleHandle(NULL);
这里的参数可以是NULL,或exe或dll
HRSRC hrsrc = FindResource(ghmodule, MAKEINTRESOURCE(idi), L"JPG");
这里的最后一个参数是这里决定的,PNG或JPG或其他
补充:
什么是句柄?为什么会有句柄?
从广义上,能够从一个数值拎起一大堆数据的东西都可以叫做句柄。句柄的英文是"Handle",本义就是"柄",只是在计算机科学中,被特别地翻译成"句柄",其实还是个"柄"。从一个小东西拎起一大堆东西,这难道不像是个"柄"吗?
然后,指针其实也是一种"句柄",只是由于指针同时拥有更特殊的含义——实实在在地对应内存里地一个地址——所以,通常不把指针说成是"句柄"。但指针也有着能从一个32位的值引用到一大堆数据的作用,这不是句柄又是什么? Windows系统中有许多内核对象(这里的对象不完全等价于"面向对象程序设计"一词中的"对象",虽然实质上还真差不多),比如打开的文件,创建的线程,程序的窗口,等等。这些重要的对象肯定不是4个字节或者8个字节足以完全描述的,他们拥有大量的属性。
为了保存这样一个"对象"的状态,往往需要上百甚至上千字节的内存空间,那么怎么在程序间或程序内部的子过程(函数)之间传递这些数据呢?拖着这成百上千的字节拷贝来拷贝去吗?显然会浪费效率。那么怎么办?
当然传递这些对象的首地址是一个办法,但这至少有两个缺点: 暴露了内核对象本身,使得程序(而不是操作系统内核)也可以任意地修改对象地内部状态(首地址都知道了,还有什么不能改的?),这显然是操作系统内核所不允许的; 操作系统有定期整理内存的责任,如果一些内存整理过一次后,对象被搬走了怎么办?
所以,Windows操作系统就采用进一步的间接:在进程的地址空间中设一张表,表里头专门保存一些编号和由这个编号对应一个地址,而由那个地址去引用实际的对象,这个编号跟那个地址在数值上没有任何规律性的联系,纯粹是个映射而已。 在Windows系统中,这个编号就叫做"句柄"。
Handle本身是一个32位的无符号整数,它用来代表一个内核对象。它并不指向实际的内核对象,用户模式下的程序永远不可能获得一个内核对象的实际地址(一般情况下)。那么Handle的意义何在?它实际上是作为一个索引在一个表中查找对应的内核对象的实际地址。那么这个表在哪里呢?每个进程都有这样的一个表,叫句柄表。该表的第一项就是进程自己的句柄,这也是为什么你调用GetCurrentProcess()总是返回0x7FFFFFFF原因。 简单地说,Handle就是一种用来"间接"代表一个内核对象的整数值。你可以在程序中使用handle来代表你想要操作的内核对象。这里的内核对象包括:事件(Event)、线程、进程、Mutex等等。我们最常见的就是文件句柄(file handle)。 另外要注意的是,Handle仅在其所属的进程中才有意义。将一个进程拥有的handle传给另一个进程没有任何意义,如果非要这么做,则需要使用DuplicateHandle(),在多个进程间传递Handle是另外一个话题了,与这里要讨论的无关。
2、进程ID 首先,进程ID是一个32位无符号整数,每个进程都有这样的一个ID,并且该ID在系统范围内是唯一的。系统使用该ID来唯一确定一个进程。 深入些说,系统可能使用进程ID来计算代表该进程的内核对象的基地址(及EPROCESS结构的基地址),具体的计算公式你可以去问微软的OS开发人员。 3、HINSTANCE HINSTANCE也是一个32无符号整数,它表示程序加载到内存中的基地址。
加载到进程地址空间的每一个可执行文件或者DLL文件都被赋予了一个独一无二的实例句柄
HMODULE和HINSTANCE 其实他们完全是一回事。如果某个函数的文档指出需要一个HMODULE参数,我们可以传入一个HINSTANCE,反之亦然。之所以有两种数据类型,是由于在16位Windows中,HMODULE和HINSTANCE表示不同类型的数据。