|
2008년 12월 21일
지난 WM_COPYDATA(1) 포스팅 된 글 중에서 다음 struct BookInfo 구조체의 m_szName 멤버 변수의 경우 사이즈가 정해져 있습니다. 그런데 만약 m_szName을 가변적으로 즉, 동적으로 메모리를 할당해서 WM_COPYDATA 메시지를 이용해서 다른 프로세스에게 데이터를 전송하기 위해서는 어떻게 해야할까요? 일감으로는 그냥 동적 할당한 후 WM_COPYDATA(1) 포스팅 내용과 동일하게 전송할 수 있을 것 같습니다. 하지만 같은 방법으로는 이 문제를 해결 할 수 없습니다.
// // 해당 프로토콜에 대해 전달 될 데이터 형 // struct BookInfo { int m_nID; TCHAR m_szName[100]; }; 그럼, 왜 안되는 걸까요?? 그건 WM_COPYDATA 메시지가 데이터를 전송해주는 방식에 있습니다. WM_COPYDATA는 COPYDATASTRUCT의 lpData 멤버변수가 가리키고 있는 메모리 주소에서 부터 cbData 멤버변수에 저장된 사이즈만큼 바이트를 읽어서 이를 복사하여 상대방 프로세스에게 데이터를 전송합니다. 우선 WM_COPYDATA(1) 에서의 경우 아래 그림과 같은 메모리가 복사되어 상대방 프로세스로 전달되기 때문에 데이터가 정상적으로 전달 되었습니다. ![]() // // 해당 프로토콜에 대해 전달 될 데이터 형 // struct BookInfo { int m_nID; LPTSTR m_szName; }; ![]() The data being passed must not contain pointers or other references toobjects not accessible to the application receiving the data. 그렇다면 이 문제를 해결하기 위해서는 어떻게 해야 할까요?? 여러가지 방법이 있겠지만 저 같은 경우는 Byte-Serializing이라는 방법을 사용해 보았습니다. Byte-Serializing은 위 구조체의 멤버를 동적으로 할당 된 메모리 공간(이하 Byte-Array)에 복사를 하는 방법으로 구조체의 멤버를 복사한 Byte-Array를 WM_COPYDATA 메시지를 이용해서 상대방 프로세스에 전달하고, 상대방 프로세는 전달 받은 Byte_Array를 De-Byte-Serializing하여 구조체의 멤버에 값을 할당해 주는 방식입니다. ![]() // // 해당 프로토콜에 대해 전달 될 데이터 형 // class CBookInfo { public: // // ByteSerializing 시 사용할 생성자 .. // CBookInfo(int arg_nID, LPTSTR arg_szName) : m_nID(arg_nID) , m_pByteData(NULL) , m_bByteSerializing(true) { m_nName = _tcslen(arg_szName) + 1; m_szName = new TCHAR[m_nName]; ZeroMemory(m_szName, m_nName); _tcsncpy(m_szName, arg_szName, m_nName); m_nByteData = sizeof(int) + m_nName; } // // DeByteSerializing 시 사용할 생성자 .. // CBookInfo(char* arg_pByteData, int arg_nByteData) : m_nID(0) , m_nName(0) , m_nByteData(arg_nByteData) , m_szName(NULL) , m_pByteData(arg_pByteData) , m_bByteSerializing(false) { } ~CBookInfo() { if(m_szName) delete[] m_szName; m_szName = NULL; // // DeByteSerializing을 하기위해 생성자에서 받은 m_pByteData는 소멸자에서 제거해서는 안된다. // if(true == m_bByteSerializing && m_pByteData) delete[] m_pByteData; m_pByteData = NULL; } char* ByteSerializing() { m_pByteData = new char[m_nByteData]; ASSERT(NULL != m_pByteData); memcpy(m_pByteData, &m_nID, sizeof(int)); memcpy(m_pByteData+sizeof(int), m_szName, m_nName); return m_pByteData; } void DeByteSerializing() { m_nName = m_nByteData - sizeof(int); m_szName = new TCHAR[m_nName]; ASSERT(m_szName); memcpy(&m_nID, m_pByteData, sizeof(int)); memcpy(m_szName, m_pByteData+sizeof(int), m_nName); } size_t GetByteDataLen() { return m_nByteData; }; int GetID() { return m_nID; } LPTSTR GetName() { return m_szName; } private: int m_nID; LPTSTR m_szName; size_t m_nName; size_t m_nByteData; char* m_pByteData; // // DeByteSerializing을 하기위해 생성자에서 받은 m_pByteData는 소멸자에서 제거해서는 안된다. // 이를 방지하기 위한 플래그 .. // bool m_bByteSerializing; }; 클래스 소스를 보시면 멤버 변수 중에 bool m_bByteSerializing; 이 보입니다. 소스를 보시면 아시겠지만 바이트 시리얼라이징을 할때와 역 바이트 시리얼라이징을 할 때 사용되는 생성자가 다릅니다. 역 바이트 시리얼 라이지을 할 때 생성자를 보시면 arg_pByteData 파라메터는 바이트 시리얼라이징 되어 전달 된 메시지 입니다. MSDN에서 WM_COPYDATA에 대한 설명을 보시면 아래와 같은 문구가 있습니다. The receiving application should not free the memory referenced by lParam. <-- lParam이 arg_pByteData로 전달 되는 값 .. 즉, arg_pByteData는 역 바이트 시리얼라이징을 이용하는 프로세스에서는 메모리 해제를 해주어서는 안된다는 것입니다. 그래서 m_bByteSerializing을 통해서 소멸자에서 arg_pByteData로 전달 된 값을 바이트 시리얼라이징 할 때만 메모리 해제 할 수 있도록 제어하는 방법을 사용하였습니다. 아래는 나머지 구현 코드입니다. ProcessA .. void CProcessADlg::OnBnClickedButton1() { // TODO: Add your control notification handler code here // // 데이터를 전송 할 프로세스의 핸들을 이용하기 위해 윈도우 객체를 얻어 옵니다. // CWnd* pWnd = FindWindow(NULL, "ProcessB"); ASSERT(pWnd); // // 전송할 데이터를 셋팅합니다. // CBookInfo bookInfo(1000, _T("Keep going ..")); // // 전송할 데이터를 COPYDATASTURCT에 셋팅하고 전송합니다. // COPYDATASTRUCT cds; cds.dwData = Protocol::PROTOCOL_BOOKINFO; cds.cbData = (DWORD)bookInfo.GetByteDataLen(); cds.lpData = (LPVOID)bookInfo.ByteSerializing(); ::SendMessage(pWnd->m_hWnd, WM_COPYDATA, (WPARAM)GetSafeHwnd(), (LPARAM)&cds); } LRESULT CProcessADlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { // TODO: Add your specialized code here and/or call the base class switch(message) { case WM_COPYDATA: { PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT) lParam; // // 프로토콜에 따른 처리를 위해서 .. // switch(pcds->dwData) { case Protocol::PROTOCOL_BOOKINFO: { // // 전송받은 데이터(COPYDATASTRUCT 구조체)를 풀어서 BookInfo에 셋팅합니다. // CBookInfo bookInfo((char*)(pcds->lpData), pcds->cbData); bookInfo.DeByteSerializing(); // // 전송받은 데이터를 메시지 박스를 출력합니다. // CString strReceiveMsg; strReceiveMsg.Format(_T("ID : %d\tName : %s"), bookInfo.GetID(), bookInfo.GetName()); AfxMessageBox(strReceiveMsg); break; } case Protocol::PROTOCOL_COOKINFO: { // Do something .. break; } } } } return CDialog::WindowProc(message, wParam, lParam); } ProcessB .. LRESULT CProcessBDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { // TODO: Add your specialized code here and/or call the base class switch(message) { case WM_COPYDATA: { PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT) lParam; // // 프로토콜에 따른 처리를 위해서 .. // switch(pcds->dwData) { case Protocol::PROTOCOL_BOOKINFO: { // // 전송받은 데이터(COPYDATASTRUCT 구조체)를 풀어서 BookInfo에 셋팅합니다. // CBookInfo bookInfo((char*)(pcds->lpData), pcds->cbData); bookInfo.DeByteSerializing(); // // 전송받은 데이터를 메시지 박스를 출력합니다. // CString strReceiveMsg; strReceiveMsg.Format(_T("ID : %d\tName : %s"), bookInfo.GetID(), bookInfo.GetName()); AfxMessageBox(strReceiveMsg); // // wParam으로 들어 온 윈도우 핸들을 이용해서 데이터를 전송한 프로세스에게 데이터를 에코합니다. // HWND hWnd = (HWND) wParam; ::SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM) pcds); break; } case Protocol::PROTOCOL_COOKINFO: { // Do something .. break; } } } } return CDialog::WindowProc(message, wParam, lParam); } 실행 결과는 WM_COPYDATA(1) 와 같습니다. * 참고 문헌 Windows API 정복 (가남사, 김상형 저) - 제33장 IPC 라. WM_COPYDATA * 예제 프로젝트 WM_COPYDATA_2.alz, WM_COPYDATA_2.a00, WM_COPYDATA_2.a01 이 글과 관련있는 글을 자동검색한 결과입니다 [?]
|
ABOUT
![]() 새로운 도전을 위해 약 1년간 자리를 비웁니다. 그 동안 블로그에 방문해 주신 분들께 진심으로 감사드립니다. 1년 뒤 .NET 관련 양질의 정보를 가지고 돌아오겠습니다. by greenfrog 메모장
카테고리
최근 등록된 덧글
잘 봤습니다. 그런데 저 상태에서 하얀..
by 비니 at 07/24 안녕하세요. 내용이 좋아서 참고합니다... by 김현수 at 07/09 1년뒤....너무 멀군요... 도전 성.. by rince at 06/26 좋은 내용이네요 많은 도움이 되었습니다.. by 이준배 at 06/04 좋은 정보 감사합니다^^ by 코즈 at 06/03 사랑합니다 by 최곱니다 at 05/12 좋은정보 감사합니다. by 이창열 at 05/11 좋은 정보 잘보고갑니다 그리고 제가 .. by Cherry at 04/27 답글이 늦어서 죄송합니다. 요즘 이래저.. by greenfrog at 04/20 좋은 정보 잘보고 갑니다^^ 도움이 많.. by 토끼 at 04/15 좋은 정보 감사합니다. 다음에 써먹어야.. by neptunex at 03/26 ㅎㅎ 잘 찾아보면 재미있는 플러그인 많.. by greenfrog at 03/22 예전에는 일부러 에러내고 그거찾아가는.. by 규학 at 03/13 아 ~ 그 일이었군요 ^^ 글 잘 봤어요 .. by greenfrog at 02/21 하나은행과 정말 생동감 넘쳤지요 ^^ by rince at 02/20 rince님의 생동감 넘치는 하루가 궁금.. by greenfrog at 02/20 어제, 그제 정말 생동감 넘치는 하루.. by rince at 02/19 저도 짬 비릴때 고참들이 웃기면 그것 .. by greenfrog at 02/19 전 자주 웃는 편이지요 ^^; 군대에선 .. by rince at 02/18 저도 이 만화 보고 어쩜 저런 생각 없는 .. by greenfrog at 02/17 최근 등록된 트랙백
자바로 작성된 프로그램 단 한번만 실..
by Start!!! 제 취향이 Oddly Enough와 안성맞.. by Oddly Enough 2009년 보기 시작하는 미드 by Pell's seer Blog [포토] 국민 여러분, 떡국 드시고 .. by Green Monkey Blog** MARVEL MOVIES : 아이언 맨 by 잠보니스틱스 ▶◀ 최진실씨, 삼가 고인의 명복을 .. by ** MY's kitchen ** 재미로 해보는 MBTI 검사 by A2공간 - 도움되는 글을 쓰자 러시아 극우조직 스킨헤드를 파헤친 기자 by Oddly Enough [Sleeping Through My Fingers].. by 바람나무, 생각가는대로 구글 크롬 안내서의 작지만 큰 실수 by Oddly Enough PETA, 돼지학대 농장 잠입취재 by Oddly Enough 병쭈니의 생각 by chrisjun82's me2DAY 준이아빠의 생각 by kkh1030's me2DAY 안철수가 말하는 "현대의 인재에.. by loading... 100% 이전블로그
이글루 파인더
|