Figure 2   Share

SharedMem.h

#include <afxole.h>
#include <afxmt.h>

class CSharedMemory
{
public:
    CSharedMemory ();
    CSharedMemory (UINT nSize, LPCTSTR pszName = NULL);
    virtual ~CSharedMemory ();

    BOOL Create (UINT nSize, LPCTSTR pszName = NULL);
    BOOL Delete ();
    CString GetName ();
    UINT GetSize ();
    BOOL Write (LPCVOID pBuffer, DWORD dwBytesToWrite,
                DWORD* pdwBytesWritten, DWORD dwOffset);
    BOOL Read (LPVOID pBuffer, DWORD dwBytesToRead, DWORD* pdwBytesRead,
               DWORD dwOffset);
    BOOL Lock ();
    BOOL Unlock ();
    BOOL MeFirst ();

    void* p;            // Address of memory block

protected:
    UINT m_nSize;        // Memory block size
    HANDLE m_hMapping;   // File mapping handle
    CString m_strName;   // Object name
    CMutex* m_pMutex;    // Pointer to mutex for synchronizing reads and writes
    BOOL m_bMeFirst;     // TRUE if this is the first connection
#ifdef _DEBUG
    UINT m_nLockCount;    // Lock count
#endif
};
SharedMem.cpp
#include <stdafx.h>
#include "SharedMem.h"

CSharedMemory::CSharedMemory ()
{
    m_nSize = 0;
    m_pMutex = NULL;
    m_hMapping = NULL;
    m_bMeFirst = FALSE;
    p = NULL;

#ifdef _DEBUG
    m_nLockCount = 0;
#endif
}

CSharedMemory::CSharedMemory (UINT nSize, LPCTSTR pszName)
{
    m_nSize = 0;
    m_pMutex = NULL;
    m_hMapping = NULL;
    m_bMeFirst = FALSE;
    p = NULL;

#ifdef _DEBUG
    m_nLockCount = 0;
#endif

    if (!Create (nSize, pszName))
        AfxThrowMemoryException ();
}

CSharedMemory::~CSharedMemory ()
{
    Delete ();
}

BOOL CSharedMemory::Create (UINT nSize, LPCTSTR pszName)
{
    // If the following ASSERT fires, you're calling Create on a shared
    // memory object that is already initialized. If you're going to do
    // that, you must call Delete first.
    ASSERT (m_hMapping == NULL);

    // If pszName is NULL, manufacture an object name.
    if (pszName == NULL) {
        GUID guid;
        ::CoCreateGuid (&guid);

        WCHAR wszName[64];
        ::StringFromGUID2 (guid, wszName, sizeof (wszName) / sizeof (WCHAR));

        TCHAR szName[64];
#ifdef UNICODE
        ::lstrcpy (szName, wszName);
#else
        int nCount = ::WideCharToMultiByte (CP_ACP, 0, wszName, -1,
            szName, sizeof (szName) / sizeof (TCHAR), NULL, NULL);
        ASSERT (nCount = sizeof (szName) / sizeof (TCHAR));
#endif
        pszName = szName;
    }

    // Create a file mapping object.
    HANDLE hMapping = ::CreateFileMapping ((HANDLE) 0xFFFFFFFF, NULL, 
                                           PAGE_READWRITE, 0, nSize, pszName);

    DWORD dwResult = ::GetLastError ();
    m_bMeFirst = (dwResult == ERROR_ALREADY_EXISTS) ? FALSE : TRUE;

    ASSERT (hMapping != NULL);
    ASSERT (hMapping != INVALID_HANDLE_VALUE);

    if (hMapping == NULL || hMapping == INVALID_HANDLE_VALUE)
        return FALSE;

    // Convert the handle into a pointer.
    void* pVoid = ::MapViewOfFile (hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);

    ASSERT (pVoid != NULL);

    if (pVoid == NULL) {
        ::CloseHandle (hMapping);
        return FALSE;
    }

    // Create (or connect to) a shared mutex for locking and unlocking.
    CMutex* pMutex = new CMutex (
        TRUE,                                            // Initially owned
        _T ("2A4F4F41-2FC1-11D2-8E53-006008A82731")      // Mutex name
    );

    ASSERT ((HANDLE) *pMutex != NULL);

    if ((HANDLE) *pMutex == NULL) {
        ::UnmapViewOfFile (pVoid);
        ::CloseHandle (hMapping);
        return FALSE;
    }

    // Store pertinent data for later.
    m_nSize = nSize;
    m_strName = pszName;
    m_pMutex = pMutex;
    m_hMapping = hMapping;
    p = pVoid;

    // Unlock the mutex and return.
    m_pMutex->Unlock ();
    return TRUE;
}

BOOL CSharedMemory::Delete ()
{
    // If the following ASSERT fires, you're calling Delete on a shared
    // memory object that has not been initialized.
    ASSERT (m_hMapping != NULL);

    // If either of the following ASSERTs fires, you're changing the
    // value of p. Don't do that!
    ASSERT (p != NULL);
    ASSERT (AfxIsValidAddress (p, m_nSize, FALSE));

    // This shouldn't happen, but let's check anyway.
    ASSERT (m_pMutex != NULL);

    // Clean up.
    m_nSize = 0;
    m_strName = _T ("");
    delete m_pMutex;
    m_pMutex = NULL;
    ::UnmapViewOfFile (p);
    p = NULL;
    ::CloseHandle (m_hMapping);
    m_hMapping = NULL;
    m_bMeFirst = FALSE;

#ifdef _DEBUG
    if (m_nLockCount != 0)
        TRACE0 (_T ("Warning: Deleting shared memory object with a " \
                "nonzero lock count\n"));
    m_nLockCount = 0;
#endif

    return TRUE;
}

CString CSharedMemory::GetName ()
{
    ASSERT (m_hMapping != NULL);
    return m_strName;
}

UINT CSharedMemory::GetSize ()
{
    ASSERT (m_hMapping != NULL);
    return m_nSize;
}

BOOL CSharedMemory::Write (LPCVOID pBuffer, DWORD dwBytesToWrite,
                           DWORD* pdwBytesWritten, DWORD dwOffset)
{
    ASSERT (m_hMapping != NULL);
    ASSERT (AfxIsValidAddress (p, m_nSize, TRUE));

    if (dwOffset >= m_nSize) {
        *pdwBytesWritten = 0;
        return FALSE;
    }

    DWORD dwCount = min (dwBytesToWrite, m_nSize - dwOffset);
    ::CopyMemory ((LPBYTE) p + dwOffset, pBuffer, dwCount);

    if (pdwBytesWritten != NULL)
        *pdwBytesWritten = dwCount;

    return TRUE;
}

BOOL CSharedMemory::Read (LPVOID pBuffer, DWORD dwBytesToRead,
                          DWORD* pdwBytesRead, DWORD dwOffset)
{
    ASSERT (m_hMapping != NULL);
    ASSERT (AfxIsValidAddress (p, m_nSize, FALSE));

    if (dwOffset >= m_nSize) {
        *pdwBytesRead = 0;
        return FALSE;
    }

    DWORD dwCount = min (dwBytesToRead, m_nSize - dwOffset);
    ::CopyMemory (pBuffer, (LPBYTE) p + dwOffset, dwCount);

    if (pdwBytesRead != NULL)
        *pdwBytesRead = dwCount;

    return TRUE;
}

BOOL CSharedMemory::Lock ()
{
    ASSERT (m_hMapping != NULL);
    m_pMutex->Lock ();
#ifdef _DEBUG
    m_nLockCount++;
#endif
    return TRUE;
}

BOOL CSharedMemory::Unlock ()
{
    ASSERT (m_hMapping != NULL);
    m_pMutex->Unlock ();
#ifdef _DEBUG
    m_nLockCount--;
#endif
    return TRUE;
}

BOOL CSharedMemory::MeFirst ()
{
    ASSERT (m_hMapping != NULL);
    return m_bMeFirst;
}

ShareDlg.h
// ShareDlg.h : header file

#if !defined(AFX_SHAREDLG_H__1DC5A326_23DA_11D2_BA24_D624B9604850__INCLUDED_)
#define AFX_SHAREDLG_H__1DC5A326_23DA_11D2_BA24_D624B9604850__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

/////////////////////////////////////////////////////////////////////////////
// CShareDlg dialog

class CShareDlg : public CDialog
{
// Construction
public:
    CShareDlg(CWnd* pParent = NULL);    // standard constructor

// Dialog Data
    //{{AFX_DATA(CShareDlg)
    enum { IDD = IDD_SHARE_DIALOG };
        // NOTE: the ClassWizard will add data members here
    //}}AFX_DATA

    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CShareDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL

// Implementation
protected:
    CSharedMemory* m_pMem;
    HICON m_hIcon;

    // Generated message map functions
    //{{AFX_MSG(CShareDlg)
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg void OnClose();
    afx_msg void OnPutSharedMem();
    afx_msg void OnGetSharedMem();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately
// before the previous line.

#endif // !defined(AFX_SHAREDLG_H__1DC5A326_23DA_11D2_BA24_D624B9604850__INCLUDED_)
ShareDlg.cpp
// ShareDlg.cpp : implementation file

#include "stdafx.h"
#include "SharedMem.h"
#include "Share.h"
#include "ShareDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CShareDlg dialog

CShareDlg::CShareDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CShareDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CShareDlg)
        // NOTE: the ClassWizard will add member initialization here
    //}}AFX_DATA_INIT
    // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    m_pMem = NULL;
}

void CShareDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CShareDlg)
        // NOTE: the ClassWizard will add DDX and DDV calls here
    //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CShareDlg, CDialog)
    //{{AFX_MSG_MAP(CShareDlg)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_CLOSE()
    ON_BN_CLICKED(IDC_PUT, OnPutSharedMem)
    ON_BN_CLICKED(IDC_GET, OnGetSharedMem)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CShareDlg message handlers

BOOL CShareDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon
    
    // Limit the "put" string to 64 characters.
    ((CEdit*) GetDlgItem (IDC_PUTTEXT))->LimitText (64);

    // Create a shared memory object.
    try {
        m_pMem = new CSharedMemory (
            256,                                        // Size
            _T ("394D15E1-2481-11D2-BA24-E3E9C2C82A0F") // Name
        );
    }
    catch (CMemoryException* e) {
        MessageBox (_T ("Unable to allocate shared memory"),
            _T ("Error"), MB_ICONEXCLAMATION | MB_OK);
        GetDlgItem (IDC_GET)->EnableWindow (FALSE);
        GetDlgItem (IDC_PUT)->EnableWindow (FALSE);
        e->Delete ();
    }
    return TRUE;
}

void CShareDlg::OnPaint() 
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
    }
}

HCURSOR CShareDlg::OnQueryDragIcon()
{
    return (HCURSOR) m_hIcon;
}

void CShareDlg::OnClose() 
{
    if (m_pMem != NULL) {
        delete m_pMem;
        m_pMem = NULL;
    }
    CDialog::OnClose();
}

void CShareDlg::OnPutSharedMem() 
{
#ifndef SMART_READ_WRITE
    if (m_pMem != NULL) {
        CString string;
        GetDlgItemText (IDC_PUTTEXT, string);
        ::lstrcpy ((LPTSTR) m_pMem->p, string);
    }    
#else
    if (m_pMem != NULL) {
        CString string;
        GetDlgItemText (IDC_PUTTEXT, string);
        DWORD dwCount = (string.GetLength () + 1) * sizeof (TCHAR);

        DWORD dwBytesWritten;
        m_pMem->Write (&dwCount, sizeof (dwCount), &dwBytesWritten, 0);
        m_pMem->Write (string.GetBuffer (0), dwCount, &dwBytesWritten,
                       sizeof (dwCount));
    }
#endif
}

void CShareDlg::OnGetSharedMem() 
{
#ifndef SMART_READ_WRITE
    if (m_pMem != NULL) {
        CString string = (LPCTSTR) m_pMem->p;
        SetDlgItemText (IDC_GETTEXT, string);
    }    
#else
    if (m_pMem != NULL) {
        DWORD dwCount, dwBytesRead;
        m_pMem->Read (&dwCount, sizeof (dwCount), &dwBytesRead, 0);

        TCHAR szText[256];
        m_pMem->Read (szText, dwCount, &dwBytesRead, sizeof (dwCount));
        SetDlgItemText (IDC_GETTEXT, szText);
    }
#endif
}