2016-01-30 1 views
0

J'essaie d'obtenir une communication inter-processus via des messages WM_COPYDATA. Le membre lpData de COPYDATASTRUCT ne peut pas contenir de pointeurs. Mon problème est, quelle est la différence entre les tableaux char et d'autres tableaux ou vecteurs. Lorsque j'utilise un tableau char comme ici, il envoie des messages avec succès. Mais quand j'utilise un vecteur, l'application réceptrice ne peut pas l'obtenir.WM_COPYDATA avec tableau vs vecteur

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; 

J'ai un vecteur global externe 'gOtherStructList'. Dans les différentes parties du programme, cette variable globale est remplie. Par exemple,

DWORD WINAPI foo(LPCTSTR lpchText) { 
    ... 
    if (sizeof(lpchText[0]) == 2) { 
     wcscpy(gOtherStructList[0].one, lpchText); 
    } 

    ... 
} 

Puis, quand je vous envoie cette liste globale, je suis le copier dans la variable de MYSTRUCT2 (pour des raisons non liées) avec wcscpy() pour chaque wchar_t de chaque élément.

Voilà comment j'envoie au récepteur de l'application:

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); 

Si elle fait la différence, l'application utilise la réception de ces messages comme:

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

Je comprends pourquoi nous ne pouvons pas utiliser des pointeurs pour WM_COPYDATA . Ce que je ne comprends pas, c'est quelle est la différence de ces exemples. Pourquoi pouvons-nous utiliser des tableaux char, mais pas des vecteurs?

Modifier:Édité ma question, basée sur des commentaires informatifs.

Merci

+5

[WM_COPYDATA] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms649011.aspx) peuvent rassembler un seul bloc de mémoire à travers boun de processus daries. Si vous devez communiquer des données structurées, vous devez les sérialiser et les désérialiser dans le processus de réception. Je suppose que 'OTHERSTRUCT' contient des pointeurs, directement ou indirectement. Les pointeurs ne sont valides que dans le processus d'où ils proviennent. – IInspectable

+0

OTHERSTRUCT possède 5 tableaux wchar_t. Rien de plus. Mais quand j'essaie de les copier, cela donne une erreur contrairement au premier exemple. – ilkerpyci

+0

Vous devez afficher la déclaration de 'OTHERSTRUCT' –

Répondre

2

std::vector est interne mis en œuvre à l'aide des pointeurs, de sorte que vous ne pouvez pas envoyer, mais vous pouvez envoyer ses données, car il est garanti d'être en continu dans la mémoire, et votre struct interne est un POD.

Vous obtenez le pointeur nécessaire avec std::vector::data():

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

REMARQUE: VC++ manque un peu dans le soutien de C, donc ce data() n'est pas disponible dans VS2010 ou avant. Vous pouvez le remplacer, si nécessaire avec:

cds.lpData = &my_struct.y[0]; 

Assurez-vous simplement que le vecteur n'est pas vide.

Et du côté de la réception:

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); 

Personnellement, je trouve la MYSTRUCT2 inutile et un peu trompeur.

+0

Merci pour l'exemple de code. Maintenant ça marche. Une question de plus: Quelle est la meilleure approche pour copier des données entrantes dans un vecteur déjà existant? J'ai créé un vecteur temporaire avec un constructeur comme dans votre code, puis utilisé l'opérateur d'affectation: 'gList = recvData;' Comment pouvons-nous le faire sans créer de vecteur temporaire? – ilkerpyci

+0

@ilkerpyci: Si vous utilisez C++ 11 ou une version ultérieure, alors 'std :: vector' est déplaçable, donc' gList = std :: vector (début, fin) 'fonctionne (ou' gList = std :: move (recvData) 'si vous préférez une variable nommée à une variable temporaire). Si vous êtes bloqué avec pre C++ 11 ou si vous voulez éviter les mouvements, vous pouvez écrire 'gList.clear(); gList.append (gList.end(), begin, end); – rodrigo

2

MYSTRUCT et OTHERSTRUCT contiennent toutes leurs données à l'intérieur d'eux-mêmes, il n'y a pas des pointeurs vers la mémoire en dehors, afin qu'ils puissent être transmis en l'état sous forme de blocs de mémoire via un seul WM_COPYDATA. D'autre part, contient std::vector de OTHERSTRUCT éléments.Seul le vector se trouve à l'intérieur de MYSTRUCT2 lui-même. Le vector contient en interne un pointeur (entre autres) vers un tableau OTHERSTRUCT situé ailleurs dans la mémoire. À cause de cela, MYSTRUCT2 ne peut pas être transmis tel quel comme un seul bloc de mémoire via WM_COPYDATA, il doit être publié en feuilleton dans un bloc de données à plat pour l'envoi, puis désérialisé lors de la réception, par exemple:

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