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
}