2016-01-30 1 views
0

Я пытаюсь достичь межпроцессного взаимодействия через сообщения WM_COPYDATA. Член lpData COPYDATASTRUCT не может содержать указатели. Моя проблема в том, в чем разница между массивами символов и другими массивами или векторами.WM_COPYDATA с массивом против вектора

Когда я использую массив символов, как здесь, он успешно отправляет сообщения.

typedef struct tagMYSTRUCT { 
wchar_t x[40] = {0}; 
} MYSTRUCT, *PMYSTRUCT; 

Но когда я использую вектор, получающее приложение не может его получить.

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 (по другим причинам) с wcscpy() для каждого wchar_t каждого элемента.

Это, как я отправить в приемник приложение:

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 , Я не понимаю, в чем разница этих примеров. Почему мы можем использовать массивы символов, но не векторы?

Редактировать:Отредактировал мой вопрос, на основе содержательных комментариев.

Благодаря

+5

[WM_COPYDATA] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms649011.aspx) может мобилизовать единый кусок памяти через процесс Boun daries. Если вам нужно связывать структурированные данные, вам необходимо его сериализовать и десериализовать в процессе получения. Я предполагаю, что 'OTHERSTRUCT' содержит указатели, прямо или косвенно. Указатели действительны только в том процессе, из которого они происходят. – IInspectable

+0

OTHERSTRUCT имеет 5 массивов wchar_t. Больше ничего. Но когда я пытаюсь их скопировать, это дает ошибку, в отличие от первого примера. – ilkerpyci

+0

Вы должны показать декларацию 'OTHERSTRUCT' –

ответ

2

std::vector внутренне реализована с использованием указателей, так что вы не можете отправить, но вы можете отправить свои данные, так как она гарантированно будет непрерывной в памяти, а ваша внутренняя структура является POD.

Вы получаете необходимый указатель с std::vector::data():

cds.cbData = sizeof(OTHERSTRUCT) * my_struct.y.size(); 
cds.lpData = my_struct.y.data(); 

Примечание: VC++ несколько недостатков в Си ++, так что это 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 бесполезен и немного вводит в заблуждение.

+0

Спасибо за образец кода. Теперь это работает. Еще один вопрос: каков наилучший подход для копирования входящих данных в уже существующий вектор? Я создал временный вектор с конструктором, как в вашем коде, а затем использовал оператор присваивания: 'gList = recvData;' Как мы можем это сделать без создания временного вектора? – ilkerpyci

+0

@ilkerpyci: Если вы используете C++ 11 или новее, тогда 'std :: vector' является подвижным, поэтому' gList = std :: vector (begin, end) 'просто работает (или' gList = std :: move (recvData) ', если вы хотите, чтобы именованная переменная была временной). Если вы застряли с pre C++ 11 или хотите избежать ходов, вы можете написать 'gList.clear(); gList.append (gList.end(), начало, конец); '. – rodrigo

2

MYSTRUCT и OTHERSTRUCT содержат все свои данные внутри себя, нет никаких указателей на наружную память, так что они могут быть переданы как есть в виде отдельных блоков памяти через WM_COPYDATA.

MYSTRUCT2, с другой стороны, содержит std::vector из OTHERSTRUCT элементов.Только сам vector находится внутри самого MYSTRUCT2. vector внутренне содержит указатель (между прочим) в массив OTHERSTRUCT, расположенный в другом месте в памяти. Из-за этого, MYSTRUCT2 не может быть передан как есть в виде одного блока памяти через WM_COPYDATA, она должна быть сериализовать в плоский блок данных для передачи, а затем десериализаций при получении, например:

#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; 
}