WM_COPYDATA 数组与向量
WM_COPYDATA with array vs vector
我正在尝试通过 WM_COPYDATA 消息实现进程间通信。 COPYDATASTRUCT 的 lpData 成员不能包含指针。我的问题是,char 数组和其他数组或向量有什么区别。
当我像这里一样使用字符数组时,它发送消息成功。
typedef struct tagMYSTRUCT {
wchar_t x[40] = {0};
} MYSTRUCT, *PMYSTRUCT;
但是当我使用vector时,接收应用程序无法获取它。
typedef struct tagOTHERSTRUCT {
wchar_t one[40] = { 0 };
wchar_t two[20] = { 0 };
wchar_t three[20] = { 0 };
wchar_t four[4] = { 0 };
wchar_t five[3] = { 0 };
} OTHERSTRUCT, *POTHERSTRUCT;
typedef struct tagMYSTRUCT2 {
std::vector<OTHERSTRUCT> y;
} MYSTRUCT2, *PMYSTRUCT2;
我有一个外部全局向量 'gOtherStructList'。在程序的各个部分,都填充了这个全局变量。例如,
DWORD WINAPI foo(LPCTSTR lpchText) {
...
if (sizeof(lpchText[0]) == 2) {
wcscpy(gOtherStructList[0].one, lpchText);
}
...
}
然后,当我发送这个全局列表时,我将它复制到 MYSTRUCT2 变量(出于不相关的原因),每个元素的每个 wchar_t 使用 wcscpy()。
这是我发送到接收方应用程序的方式:
MYSTRUCT2 my_struct; //my_struct.y is a vector
// Filled my_struct.y here with wcscpy()
COPYDATASTRUCT cds;
cds.dwData = MY_CASE;
cds.cbData = sizeof(OTHERSTRUCT) * my_struct.y.size();
cds.lpData = &my_struct;
SendMessage(gDataReceiver, WM_COPYDATA, NULL, (LPARAM)&cds);
如果有所不同,接收应用程序会使用这些消息,例如:
case WM_COPYDATA:
{
PCOPYDATASTRUCT pcopydata = (PCOPYDATASTRUCT)lParam;
switch (pcopydata->dwData) {
case MY_CASE:
// When I code this, it works
PMYSTRUCT p = (PMYSTRUCT)(pcopydata->lpData);
wcscpy(mylocalvar, p->x); // for char array
...
// But, this doesn't work.
std::cout << "New message received" << std::endl; // this gets printed, then program crashes.
PMYSTRUCT2 p = (PMYSTRUCT2)(pcopydata->lpData);
OTHERSTRUCT mylocallist[100],
wcscpy(mylocallist[0].one, p->y[0].one);
}
我明白为什么我们不能为 WM_COPYDATA 使用指针。我不明白的是,这些例子有什么区别。为什么我们可以使用字符数组而不是向量?
编辑: 根据信息性评论编辑了我的问题。
谢谢
std::vector
内部是用指针实现的,所以你不能发送那个,但是你可以发送它的数据,因为它保证在内存中是连续的,而且你的内部结构是一个POD。
您通过 std::vector::data()
获得了必要的指针:
cds.cbData = sizeof(OTHERSTRUCT) * my_struct.y.size();
cds.lpData = my_struct.y.data();
注意:VC++ 缺少对 C++ 的支持,因此此 data()
在 VS2010 或更早版本中不可用。如果需要,您可以将其替换为:
cds.lpData = &my_struct.y[0];
只要确保向量不为空即可。
在接收方:
OTHERSTRUCT *begin = static_cast<OTHERSTRUCT*>(pcopydata->lpData);
OTHERSTRUCT *end = begin + pcopydata->cbData / sizeof(OTHERSTRUCT);
//copy the data into a vector, or treat them directly
std::vector<OTHERSTRUCT> recvData(begin, end);
我个人认为 MYSTRUCT2
没用而且有点误导。
MYSTRUCT
和 OTHERSTRUCT
包含它们自己内部的所有数据,没有指向外部内存的指针,因此它们可以通过 [=15= 按原样作为单个内存块传输].
另一方面,MYSTRUCT2
包含 std::vector
个 OTHERSTRUCT
元素。只有 vector
本身位于 MYSTRUCT2
本身内部。 vector
内部包含一个指向位于内存中其他地方的 OTHERSTRUCT
数组的指针(除其他外)。正因为如此,MYSTRUCT2
无法通过WM_COPYDATA
作为单个内存块原样传输,需要序列化成一个扁平的数据块发送,接收时再反序列化,eg:
#pragma pack(push, 1)
typedef struct tagMYCDSDATA {
int numItems;
OTHERSTRUCT items[1];
} MYCDSDATA, *PMYCDSDATA;
#pragma pack(pop)
MYSTRUCT2 my_struct;
// Fill my_struct.y as needed...
int count = my_struct.y.size();
std::vector<BYTE> buffer(sizeof(int) + (sizeof(OTHERSTRUCT) * count));
PMYCDSDATA cdsdata = reinterpret_cast<PMYCDSDATA>(&buffer[0]);
//or, if using C++11: PMYCDSDATA cdsdata = reinterpret_cast<PMYCDSDATA>(buffer.data());
data->numItems = count;
std::copy(my_struct.y.begin(), my_struct.y.end(), data->items);
COPYDATASTRUCT cds;
cds.dwData = MY_CASE;
cds.cbData = buffer.size();
cds.lpData = cdsdata;
SendMessage(gDataReceiver, WM_COPYDATA, NULL, reinterpret_cast<LPARAM>(&cds));
case WM_COPYDATA:
{
PCOPYDATASTRUCT pcopydata = reinterpret_cast<PCOPYDATASTRUCT>(lParam);
if (pcopydata->dwData == MY_CASE)
{
std::cout << "New message received" << std::endl;
PMYCDSDATA p = static_cast<PMYCDSDATA>(pcopydata->lpData);
for(int i = 0; i < p->numItems; ++i)
{
// use p->item[i].one, etc as needed...
}
return 0;
}
break;
}
我正在尝试通过 WM_COPYDATA 消息实现进程间通信。 COPYDATASTRUCT 的 lpData 成员不能包含指针。我的问题是,char 数组和其他数组或向量有什么区别。
当我像这里一样使用字符数组时,它发送消息成功。
typedef struct tagMYSTRUCT {
wchar_t x[40] = {0};
} MYSTRUCT, *PMYSTRUCT;
但是当我使用vector时,接收应用程序无法获取它。
typedef struct tagOTHERSTRUCT {
wchar_t one[40] = { 0 };
wchar_t two[20] = { 0 };
wchar_t three[20] = { 0 };
wchar_t four[4] = { 0 };
wchar_t five[3] = { 0 };
} OTHERSTRUCT, *POTHERSTRUCT;
typedef struct tagMYSTRUCT2 {
std::vector<OTHERSTRUCT> y;
} MYSTRUCT2, *PMYSTRUCT2;
我有一个外部全局向量 'gOtherStructList'。在程序的各个部分,都填充了这个全局变量。例如,
DWORD WINAPI foo(LPCTSTR lpchText) {
...
if (sizeof(lpchText[0]) == 2) {
wcscpy(gOtherStructList[0].one, lpchText);
}
...
}
然后,当我发送这个全局列表时,我将它复制到 MYSTRUCT2 变量(出于不相关的原因),每个元素的每个 wchar_t 使用 wcscpy()。
这是我发送到接收方应用程序的方式:
MYSTRUCT2 my_struct; //my_struct.y is a vector
// Filled my_struct.y here with wcscpy()
COPYDATASTRUCT cds;
cds.dwData = MY_CASE;
cds.cbData = sizeof(OTHERSTRUCT) * my_struct.y.size();
cds.lpData = &my_struct;
SendMessage(gDataReceiver, WM_COPYDATA, NULL, (LPARAM)&cds);
如果有所不同,接收应用程序会使用这些消息,例如:
case WM_COPYDATA:
{
PCOPYDATASTRUCT pcopydata = (PCOPYDATASTRUCT)lParam;
switch (pcopydata->dwData) {
case MY_CASE:
// When I code this, it works
PMYSTRUCT p = (PMYSTRUCT)(pcopydata->lpData);
wcscpy(mylocalvar, p->x); // for char array
...
// But, this doesn't work.
std::cout << "New message received" << std::endl; // this gets printed, then program crashes.
PMYSTRUCT2 p = (PMYSTRUCT2)(pcopydata->lpData);
OTHERSTRUCT mylocallist[100],
wcscpy(mylocallist[0].one, p->y[0].one);
}
我明白为什么我们不能为 WM_COPYDATA 使用指针。我不明白的是,这些例子有什么区别。为什么我们可以使用字符数组而不是向量?
编辑: 根据信息性评论编辑了我的问题。
谢谢
std::vector
内部是用指针实现的,所以你不能发送那个,但是你可以发送它的数据,因为它保证在内存中是连续的,而且你的内部结构是一个POD。
您通过 std::vector::data()
获得了必要的指针:
cds.cbData = sizeof(OTHERSTRUCT) * my_struct.y.size();
cds.lpData = my_struct.y.data();
注意:VC++ 缺少对 C++ 的支持,因此此 data()
在 VS2010 或更早版本中不可用。如果需要,您可以将其替换为:
cds.lpData = &my_struct.y[0];
只要确保向量不为空即可。
在接收方:
OTHERSTRUCT *begin = static_cast<OTHERSTRUCT*>(pcopydata->lpData);
OTHERSTRUCT *end = begin + pcopydata->cbData / sizeof(OTHERSTRUCT);
//copy the data into a vector, or treat them directly
std::vector<OTHERSTRUCT> recvData(begin, end);
我个人认为 MYSTRUCT2
没用而且有点误导。
MYSTRUCT
和 OTHERSTRUCT
包含它们自己内部的所有数据,没有指向外部内存的指针,因此它们可以通过 [=15= 按原样作为单个内存块传输].
MYSTRUCT2
包含 std::vector
个 OTHERSTRUCT
元素。只有 vector
本身位于 MYSTRUCT2
本身内部。 vector
内部包含一个指向位于内存中其他地方的 OTHERSTRUCT
数组的指针(除其他外)。正因为如此,MYSTRUCT2
无法通过WM_COPYDATA
作为单个内存块原样传输,需要序列化成一个扁平的数据块发送,接收时再反序列化,eg:
#pragma pack(push, 1)
typedef struct tagMYCDSDATA {
int numItems;
OTHERSTRUCT items[1];
} MYCDSDATA, *PMYCDSDATA;
#pragma pack(pop)
MYSTRUCT2 my_struct;
// Fill my_struct.y as needed...
int count = my_struct.y.size();
std::vector<BYTE> buffer(sizeof(int) + (sizeof(OTHERSTRUCT) * count));
PMYCDSDATA cdsdata = reinterpret_cast<PMYCDSDATA>(&buffer[0]);
//or, if using C++11: PMYCDSDATA cdsdata = reinterpret_cast<PMYCDSDATA>(buffer.data());
data->numItems = count;
std::copy(my_struct.y.begin(), my_struct.y.end(), data->items);
COPYDATASTRUCT cds;
cds.dwData = MY_CASE;
cds.cbData = buffer.size();
cds.lpData = cdsdata;
SendMessage(gDataReceiver, WM_COPYDATA, NULL, reinterpret_cast<LPARAM>(&cds));
case WM_COPYDATA:
{
PCOPYDATASTRUCT pcopydata = reinterpret_cast<PCOPYDATASTRUCT>(lParam);
if (pcopydata->dwData == MY_CASE)
{
std::cout << "New message received" << std::endl;
PMYCDSDATA p = static_cast<PMYCDSDATA>(pcopydata->lpData);
for(int i = 0; i < p->numItems; ++i)
{
// use p->item[i].one, etc as needed...
}
return 0;
}
break;
}