IPC통신 프로그램 작성 순서

 

1.공유메모리(반드시 Virtual Memory공간) 할당, 초기화

2. 문자열을 수신하는 이벤트 생성

3. 이벤트(신호)를 감시하는 스레드 생성

4. 수신한 문자열을 화면에 출력(사용자 정의 메시지 이용)

5. 문자열을 전송하는 부분을 뮤텍스 객체로 동기화

전송하는 쪽에서 스레드를 동기화 시켜야 하는 이유(뮤텍스를 이용하는 이유)

-> 전송하는 응용프로그램이 공유메모리를 쓰는 동안은 다른 프로세스가 접근하지 못하도록 막아두는 것

(동기화 되는 타이밍이 맞지 않을 수 있어 크리티컬 섹션보다는 커널 객체인 뮤택스를 사용한다)

 

 

1. 대화상자 기반의 새 프로젝트(SharedMem) 생성

 

2. 화면구성

버튼1, 리스트박스1, 에디트컨트롤1 추가

 

3. SharedMem.h파일에 객체 선언

class CSharedMemApp : public CWinApp
{
public:
 CSharedMemApp();

 HANDLE m_hMap;
 TCHAR* m_pSharedMemory;
 CMutex m_Mutex;

 CEvent m_ExitEvent;
 CEvent m_ReadEvent;

 

4. SharedMem.cpp에 객체 초기화

4.1 세 개의 커널 객체 초기화

CSharedMemApp::CSharedMemApp()
:m_Mutex(FALSE, TEXT("IPC_TEST_MUTEX")),        //뮤텍스객체 초기화, 이름지어줌
m_ExitEvent(FALSE, TRUE),

m_ReadEvent(FALSE, TRUE, _T("IPC_READ_SHAREDMEMORY"))    //이벤트객체 초기화, 이름지어줌

{

.

.

.

 

4.2 두개의 핸들과 TCHAR* 초기화

CSharedMemApp::CSharedMemApp()
:m_Mutex(FALSE, TEXT("IPC_TEST_MUTEX")),
m_ExitEvent(FALSE, TRUE),
m_ReadEvent(FALSE, TRUE, _T("IPC_READ_SHAREDMEMORY"))
{
     m_hMap                          =NULL;
     m_pSharedMemory           =NULL;

     // TODO: 여기에 생성 코드를 추가합니다.
     // InitInstance에 모든 중요한 초기화 작업을 배치합니다.
}

 

5. <공유메모리를 할당하고 초기화 하는 프로그램 작성> ->자체를 함수로 만들어서 불러오도록 할것임 (SharedMem.cpp에)

함수 만들기

BOOL CSharedMemApp::InitSharedMemory(void)

{

}

 

함수 만들고 바로 헤더파일에서 원형 선언해줌. 잊어버리지 않도록.

BOOL InitSharedMemory(void);

 

코드 작성

BOOL CSharedMemApp::InitSharedMemory(void)
{
     m_hMap   =::CreateFileMapping( INVALID_HANDLE_VALUE,
                                                    NULL,
                                                    PAGE_READWRITE,
                                                    0,
                                                    sizeof(TCHAR)*128,
                                                    _T("IPC_TEST_SHARED_MEMORY"));
     if (::GetLastError() != ERROR_ALREADY_EXISTS)
     {
          m_hMap = ::OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE,
             _T("IPC_TEST_SHARED_MEMORY")); //공유메모리에 파일공간을 만들어 줌
     }

 

     if (m_hMap == NULL)
     {
          AfxMessageBox(_T("ERROR : Failed to create(open) file mapping object!")); // 예외처리:공유메모리가 할당되지 않았을경우 에러메시지 출력
          return FALSE;
     }
 
     m_pSharedMemory = (TCHAR*)::MapViewOfFile( m_hMap,
                                                                          FILE_MAP_ALL_ACCESS,
                                                                          0,
                                                                          0,
                                                                          sizeof(TCHAR)*128);
     if (m_pSharedMemory == NULL)
     {
          AfxMessageBox(_T("ERROR : Failed to get shared memory!")); // 예외처리:공유메모리에 문자열이 없다면 파일생성 하지 않음
          return FALSE;
     }

     return TRUE;
}

 

함수 설명

CreateFileMapping()     // 가상메모리 커널모드 공간에 실제 값을 넣을 수 있는 공간을 만들어줌

pSharedMemory           // 문자를 가리킬 수있는 포인터

MapViewOfFile()          // 전체공간(sizeof(TCHAR)*128)안의 값을 전부다 가지고 오도록 함(통째로). 이 때 실제 값을 가져오는것이 아니라 포인터로 가리키도록 함. (들어가 있는 값만을 가지고 오고자 할 때는 for/while문을 사용하여 null문자를 만날때까지 반복해서 문자를 가져오도록 해야한다.)

 

6.

int CSharedMemApp::ExitInstance()
{
     if(m_pSharedMemory != NULL)  ::UnmapViewOfFile(m_pSharedMemory);
     if(m_hMap != NULL)                 ::CloseHandle(m_hMap);

 

     return CWinApp::ExitInstance();
}

 

7.

BOOL CSharedMemApp::InitInstance()
{
     if (!InitSharedMemory()) return FALSE;

.

.

.

 

<문자열을 수신할 수 있도록 이벤트 객체 생성하고 스레드 만들기>

1. App클래스에 스레드 함수 생성(스레드 함수는 되도록 마법사로...)

 

// 문자열 수신을 위한 이벤트 객체의 생성
UINT CSharedMemApp::ThreadReadSharedMemory(LPVOID pParam)
{
     return 0;
}     // 이벤트가 들어오는 것을 기다리는 함수를 작성(리스너)

 

// 문자열 수신을 위한 이벤트 객체의 생성
UINT CSharedMemApp::ThreadReadSharedMemory(LPVOID pParam)
{
     DWORD dwResult = WAIT_OBJECT_0+1;
     HANDLE arhList[2];
     arhList[0] = theApp.m_ExitEvent;
     arhList[1] = theApp.m_ReadEvent;

 

     while(dwResult == WAIT_OBJECT_0+1)
     {
          dwResult = ::WaitForMultipleObjects(2, arhList, FALSE, INFINITE);
          if(dwResult == WAIT_OBJECT_0)
          {break;}
          else if(dwResult == WAIT_OBJECT_0+1)
          {
               theApp.m_pMainWnd->PostMessage(UM_RECV_EVENT);
               ::Sleep(10);
          }
     }
     return 0;
}//ExitEvent가 나오면 빠져나오도록 조건을 준다

 

 

2. User Message작성(UM_RECV_EVENT), stdafx.h파일에

#define UM_RECV_EVENT WM_USER + 100

 

3.

BOOL CSharedMemApp::InitInstance()
{
     if (!InitSharedMemory()) return FALSE;
     AfxBeginThread(CSharedMemApp::ThreadReadSharedMemory, NULL);

.

.

.


 

<수신 받았을 때 화면에 출력. Dlg클래스>

1. Dlg클래스의 헤더파일에  선언

 

public:
 CListBox m_List;
 CString m_csMessage;

 

2. 특정 메시지에 대응하는 이벤트 처리기 직접 만듬(SharedMemDlg.cpp)

RESULT CSharedMemDlg::OnRecvEvent(WPARAM wParam, LPARAM lParam)
{
     m_List.InsertString(0, theApp.m_pSharedMemory);

     return 0;
}

 

3. 메시지 맵에 작성

BEGIN_MESSAGE_MAP(CSharedMemDlg, CDialog)
     ON_WM_SYSCOMMAND()
     ON_WM_PAINT()
     ON_WM_QUERYDRAGICON()
     //}}AFX_MSG_MAP
     ON_BN_CLICKED(IDC_BUTTON1, &CSharedMemDlg::OnBnClickedButton1)
     ON_MESSAGE(UM_RECV_EVENT, &CSharedMemDlg::OnRecvEvent)
END_MESSAGE_MAP()

 

 

헤더파일(SharedMemDlg.h)의 메시지 맵 함수에도 선언

 

     // 생성된 메시지 맵 함수
     virtual BOOL OnInitDialog();
     afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
     afx_msg void OnPaint();
     afx_msg HCURSOR OnQueryDragIcon();
     DECLARE_MESSAGE_MAP()
public:
     afx_msg LRESULT OnRecvEvent(WPARAM wParam, LPARAM lParam);
     afx_msg void OnBnClickedButton1(); 
};

 

<버튼 클릭 이벤트 처리기>

void CSharedMemDlg::OnBnClickedButton1()
{
     if(!UpdateData(TRUE) || m_csMessage.GetLength() <= 0)
      return;

 

     if(theApp.m_Mutex.Lock(1000))
     {
          CEvent EventSend(FALSE, TRUE, _T("IPC_READ_SHAREDMEMORY"));
          wsprintf(theApp.m_pSharedMemory, _T("%s"), m_csMessage);

          

         EventSend.SetEvent();
          ::Sleep(1);
  

         EventSend.ResetEvent();
          theApp.m_Mutex.Unlock();
     }
     else
     {
          AfxMessageBox(_T("ERROR : Lock() Function is return FALSE!!"));
     }
     m_csMessage = _T("");
     UpdateData(FALSE);
}

 

<아래코드 추가>

 

void CSharedMemDlg::DoDataExchange(CDataExchange* pDX)
{
     CDialog::DoDataExchange(pDX);
     DDX_Control(pDX, IDC_LIST1, m_List);
     DDX_Text(pDX, IDC_EDIT1, m_csMessage);
     DDV_MaxChars(pDX, m_csMessage, 64);
}


'PROGRAMMING > MFC(C++)' 카테고리의 다른 글

[0425수업] dll파일 만들기  (0) 2011.04.25
[0425수업] ClipBoard  (0) 2011.04.25
[0422수업] 중복실행 방지  (0) 2011.04.22
[0421수업] 소프트웨어 업데이트  (0) 2011.04.21
[0421수업] 세마포어  (0) 2011.04.21
Posted by 마마필로 :