www.pudn.com > SuperOPC-vc7.rar > HotOpcServer.h
#pragma once #include#include "comm\opcda.h" #include "comm\opccomn.h" #include #define _countof(array) (sizeof(array)/sizeof(array[0])) #define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } #define VERSION_1 1 #define CURRENT_VERSION VERSION_1 // OPC_XX_DATAXX defines are based on an index in a listbox (do not modify) #define OPC_10_DATACHANGE 0 // OnDataChange 1.0 no timestamp request #define OPC_10_DATATIMECHANGE 1 // OnDataChange 1.0 with timestamp request #define OPC_20_DATACHANGE 2 // OnDataChange 2.0 (always a timestamp) request #define OPC_NO_QUALITY_NO_VALUE 0xFF #define OPC_QUALITY_BAD_NON_SPECIFIC 0x0 #define OPC_QUALITY_BAD_CONFIG_ERR0R 0x04 #define OPC_QUALITY_BAD_NOT_CONNECTED 0x08 #define OPC_QUALITY_BAD_DEVICE_FAILURE 0x0C #define OPC_QUALITY_BAD_SENSOR_FAILURE 0x10 #define OPC_QUALITY_BAD_LAST_KNOWN_VALUE 0x14 #define OPC_QUALITY_BAD_COMM_FAILURE 0x18 #define OPC_QUALITY_BAD_OUT_OF_SERVICE 0x1C #define OPC_QUALITY_UNCERTAIN_NON_SPECIFIC 0x40 #define OPC_QUALITY_UNCERTAIN_LAST_USABLE_VALUE 0x44 #define OPC_QUALITY_UNCERTAIN_SENSOR_NOT_ACCURATE 0x50 #define OPC_QUALITY_UNCERTAIN_EU_UNITS_EXCEEDED 0x54 #define OPC_QUALITY_UNCERTAIN_SUB_NORMAL 0x58 #define OPC_QUALITY_GOOD_NON_SPECIFIC 0xC0 #define OPC_QUALITY_GOOD_LOCAL_OVERRIDE 0xD8 #define OPC_QUALITY_LIMITFIELD_NOT 0x0 #define OPC_QUALITY_LIMITFIELD_LOW 0x1 #define OPC_QUALITY_LIMITFIELD_HIGH 0x2 #define OPC_QUALITY_LIMITFIELD_CONSTANT 0x3 // group defaults #define GROUP_DEFAULT_ACTIVESTATE TRUE #define GROUP_DEFAULT_LANGUAGEID MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US) #define GROUP_DEFAULT_NAME _T("") #define GROUP_DEFAULT_DEADBAND 0.0f #define GROUP_DEFAULT_TIMEBIAS 0 #define GROUP_DEFAULT_UPDATERATE 100 #define GROUP_DEFAULT_UPDATEMETHOD OPC_20_DATACHANGE #define GROUP_DEFAULT_FORCEDELETE FALSE #define GROUP_DEFAULT_REMOVEITEMSONDELETE TRUE #define GROUP_DEFAULT_ACTIVATEITEMSONSELECT TRUE // item defaults #define ITEM_DEFAULT_ACCESSPATH _T("") #define ITEM_DEFAULT_ITEMID _T("") #define ITEM_DEFAULT_ACTIVESTATE TRUE #define ITEM_DEFAULT_DATATYPE VT_EMPTY #define MQI_IOPCSERVER 0 #define MQI_IOPCCOMMON 1 #define MQI_IOPCCONNPT 2 #define MQI_IOPCITEMPROP 3 #define MQI_IOPCBROWSE 4 #define MQI_IOPCPUBLIC 5 #define MQI_IOPCPERSIST 6 /*// Clipboard formats for data access 1.0 streams: UINT CF_DATA_CHANGE = RegisterClipboardFormat (_T("OPCSTMFORMATDATA")); UINT CF_DATA_CHANGE_TIME = RegisterClipboardFormat (_T("OPCSTMFORMATDATATIME")); UINT CF_WRITE_COMPLETE = RegisterClipboardFormat (_T("OPCSTMFORMATWRITECOMPLETE")); // Clipboard formats for cut/copy/paste: UINT CF_SERVER = RegisterClipboardFormat (_T("QCOpcClientServer")); UINT CF_GROUP = RegisterClipboardFormat (_T("QCOpcClientGroup")); UINT CF_ITEM = RegisterClipboardFormat (_T("QCOpcClientItem"));*/ VARTYPE VartypeFromString (LPCTSTR lpszType); void StringFromVartype (VARTYPE vtType, CString &strType); class IHotShutdown; class CHotOpcGroup; class CHotOpcItem; class CFixedSharedFile; // CHotOpcServer 命令目标 /*--------------------------------------------- CHotOpcServer类 desc:... ----------------------------------------------*/ class CHotOpcServer : public CObject { public: CHotOpcServer(); CHotOpcServer(CString &strSerName,CString strRemote); virtual ~CHotOpcServer(); protected: //声明OPC相应接口 IOPCServer *m_pIServer; IOPCCommon *m_pICommon; IConnectionPointContainer *m_pIConnPtContainer; IOPCItemProperties *m_pIItemProps; IOPCBrowseServerAddressSpace *m_pIBrowse; IOPCServerPublicGroups *m_pIPublicGroups; IPersistFile *m_pIPersistFile; IHotShutdown *m_pIShutdownSink; DWORD m_dwCookieShutdown; MULTI_QI m_arrMultiQI[7]; //接口数组,用于查询服务 typedef struct S_Flags { DWORD bIsKepServerEx : 1; DWORD Reserved : 31; } FLAGS; FLAGS m_bfFlags; CStringList *m_pServerList; //服务器名列表 CString m_strServerName; //服务器名称 CString m_strRemoteMachine;//机器地址或名 bool m_bConnected; // 列表管理 CHotOpcServer *m_pPrev; CHotOpcServer *m_pNext; // 组管理 CHotOpcGroup *m_pGroupHead; DWORD m_cdwGroups; void InitInterface(void); HRESULT GetCLSID (CLSID &clsid); public: INT DisplayComponent(BOOL bOpc2 = TRUE); INT GetServerCount(void); CString GetServerNameByIndex(int nIndex); void SetServerName (CString &strSerName); LPCTSTR GetServerName() {return (m_strServerName);} void SetRemoteMachine (CString &strRemoteMachine); LPCTSTR GetRemoteMachine () { if (m_strRemoteMachine.IsEmpty ()) return (NULL); return (m_strRemoteMachine); } void ShutdownRequest (LPCTSTR lpszReason); bool Connect (CString &strSerName, CString &strRemoteMachine); bool Connect(void); void Disconnect(void); bool IsConnected () {return (m_bConnected);} bool IsKepServerEx () {return (m_bfFlags.bIsKepServerEx);} bool IsAlive (); void Start (); void Stop (); // cut/copy/paste void Copy (CFixedSharedFile &sf); void Paste (CFixedSharedFile &sf); // list management void SetPrev (CHotOpcServer *pPrev) {m_pPrev = pPrev;} CHotOpcServer* GetPrev () {return (m_pPrev);} void SetNext (CHotOpcServer *pNext) {m_pNext = pNext;} CHotOpcServer* GetNext () {return (m_pNext);} // group management void AddGroup (CHotOpcGroup *pGroup, bool bLoadingProject = false); void AddClonedGroup (CHotOpcGroup *pClone); void RemoveGroup (CHotOpcGroup *pGroup, bool bDelete = true); void RemoveAllGroups (bool bDelete = true); CHotOpcGroup* GetGroupHead () {return (m_pGroupHead);} bool GenerateGroupName (CString &strName); bool FindGroup (LPCTSTR lpszName); CHotOpcGroup *GetGroup (LPCTSTR lpszName); // 所支持的接口 bool IsIServerSupported () {return (m_pIServer != NULL);} bool IsICommonSupported () {return (m_pICommon != NULL);} bool IsIConnectionPointContainerSupported () {return (m_pIConnPtContainer != NULL);} bool IsIItemPropertiesSupported () {return (m_pIItemProps != NULL);} bool IsIBrowsingSupported () {return (m_pIBrowse != NULL);} bool IsIServerPublicGroupsSupported () {return (m_pIPublicGroups != NULL);} bool IsIPersistFileSupported () {return (m_pIPersistFile != NULL);} IOPCServer* GetIServer () {return (m_pIServer);} IOPCBrowseServerAddressSpace* GetIBrowse () {return (IsAlive () ? m_pIBrowse : NULL);} IOPCItemProperties* GetIItemProps () {return (m_pIItemProps);} virtual void Serialize(CArchive& ar); }; // ************************************************************************** class CSafeLock { public: CSafeLock (CSyncObject *pso) { ASSERT (pso); pso->Lock (); m_pso = pso; } ~CSafeLock () { m_pso->Unlock (); } private: CSyncObject *m_pso; }; class CSafeArray : public SAFEARRAY { public: CSafeArray (const CSafeArray &cSrc); CSafeArray (WORD wRows, WORD wCols, WORD wBytesPerElement, void *pData = NULL); CSafeArray (DWORD cdwElements, WORD wBytesPerElement, void *pData = NULL); ~CSafeArray (); // Returns the length of the array in bytes DWORD GetByteLength () const; // Returns the number of elements in the array DWORD GetNumElements () const; DWORD GetNumRows () const; DWORD GetNumCols () const; // So we can send to a CF_TEXT client void Format (CString &str, VARTYPE vt) const; // Assigment as a vector void operator = (const SAFEARRAY &cSrc); // Overloaded operators to construct/destroy void *operator new (size_t s); void operator delete (void *p); // Comparison bool operator == (const SAFEARRAY &cSrc) const; bool operator != (const SAFEARRAY &cSrc) const {return !(*this == cSrc);} protected: void Alloc (DWORD dwBytes); }; //------------------------------------------------------ //继续IOPCShutdown接口 /*--------------------------------------------- CHotOpcServer类 desc:... ----------------------------------------------*/ class IHotShutdown : public IOPCShutdown { public: IHotShutdown (CHotOpcServer *pServer); ~IHotShutdown (); // 实现IUnknow接口方法 STDMETHODIMP QueryInterface (REFIID iid, LPVOID *ppInterface); STDMETHODIMP_(ULONG) AddRef (); STDMETHODIMP_(ULONG) Release (); // IOPCShutdown 接口方法 STDMETHODIMP ShutdownRequest (LPCWSTR lpwszReason); private: DWORD m_cnRef; CHotOpcServer *m_pServer; }; class IKDataSink20 : public IOPCDataCallback { public: IKDataSink20 (); ~IKDataSink20 (); // IUnknown Methods STDMETHODIMP QueryInterface (REFIID iid, LPVOID *ppInterface); STDMETHODIMP_(ULONG) AddRef (); STDMETHODIMP_(ULONG) Release (); // IOPCDataCallback Methods STDMETHODIMP OnDataChange ( // OnDataChange notifications DWORD dwTransID, // 0 for normal OnDataChange events, non-zero for Refreshes OPCHANDLE hGroup, // client group handle HRESULT hrMasterQuality, // S_OK if all qualities are GOOD, otherwise S_FALSE HRESULT hrMasterError, // S_OK if all errors are S_OK, otherwise S_FALSE DWORD dwCount, // number of items in the lists that follow OPCHANDLE *phClientItems, // item client handles VARIANT *pvValues, // item data WORD *pwQualities, // item qualities FILETIME *pftTimeStamps, // item timestamps HRESULT *pErrors); // item errors STDMETHODIMP OnReadComplete ( // OnReadComplete notifications DWORD dwTransID, // Transaction ID returned by the server when the read was initiated OPCHANDLE hGroup, // client group handle HRESULT hrMasterQuality, // S_OK if all qualities are GOOD, otherwise S_FALSE HRESULT hrMasterError, // S_OK if all errors are S_OK, otherwise S_FALSE DWORD dwCount, // number of items in the lists that follow OPCHANDLE *phClientItems, // item client handles VARIANT *pvValues, // item data WORD *pwQualities, // item qualities FILETIME *pftTimeStamps, // item timestamps HRESULT *pErrors); // item errors STDMETHODIMP OnWriteComplete ( // OnWriteComplete notifications DWORD dwTransID, // Transaction ID returned by the server when the write was initiated OPCHANDLE hGroup, // client group handle HRESULT hrMasterError, // S_OK if all errors are S_OK, otherwise S_FALSE DWORD dwCount, // number of items in the lists that follow OPCHANDLE *phClientItems, // item client handles HRESULT *pErrors); // item errors STDMETHODIMP OnCancelComplete ( // OnCancelComplete notifications DWORD dwTransID, // Transaction ID provided by the client when the read/write/refresh was initiated OPCHANDLE hGroup); private: DWORD m_cnRef; }; // ************************************************************************** class CKAdviseSink : public IAdviseSink { public: CKAdviseSink (); // IUnknown Methods STDMETHODIMP QueryInterface (REFIID riid, LPVOID *ppInterface); STDMETHODIMP_(ULONG) AddRef (); STDMETHODIMP_(ULONG) Release (); // IAdviseSink Methods STDMETHODIMP_(void) OnDataChange (FORMATETC *pFormatEtc, STGMEDIUM *pMedium); STDMETHODIMP_(void) OnViewChange (unsigned long dwAspect, long lindex) {/*Not implemented*/}; STDMETHODIMP_(void) OnRename (LPMONIKER pmk) {/*Not implemented*/}; STDMETHODIMP_(void) OnSave () {/*Not implemented*/}; STDMETHODIMP_(void) OnClose () {/*Not implemented*/}; private: protected: ULONG m_cRef; }; // ************************************************************************** // CHotOpcGroup 命令目标 /*--------------------------------------------- CHotOpcGroup类 desc:... ----------------------------------------------*/ class CHotOpcGroup : public CObject { public: // construction/destruction CHotOpcGroup (CHotOpcServer *pParent); ~CHotOpcGroup (); public: // property accessor/manipulators void SetName (CString &strName) {m_strName = strName;} void SetName (LPCTSTR lpszName) {m_strName = lpszName;} LPCTSTR GetName () {return (m_strName);} void SetUpdateRate (DWORD dwRate) {m_dwUpdateRate = dwRate;} DWORD GetUpdateRate () {return (m_dwUpdateRate);} void SetLanguageID (LCID lcid) {m_dwLanguageID = lcid;} LCID GetLanguageID () {return (m_dwLanguageID);} void SetActive (BOOL bActive, BOOL bApply = FALSE) { /*m_bActive = bActive; // apply change to server now if (bApply && m_pIGroupState) { DWORD dwRevRate; // for [out] parm m_pIGroupState->SetState (NULL, &dwRevRate, &m_bActive, NULL, NULL, NULL, NULL); // select the activated group CKMainWnd *pWnd = (CKMainWnd *) AfxGetMainWnd (); if (pWnd) pWnd->PostMessage (UM_SELECT_GROUP, 0, (LPARAM) this); // log status LogMsg (IDS_SET_GROUP_ACTIVE_STATE, bActive, GetName ()); }*/ } BOOL IsActive () {return (m_bActive);} void SetBias (long lBias) {m_lBias = lBias;} long GetBias () {return (m_lBias);} void SetDeadband (float fDeadband) {m_fDeadband = fDeadband;} float GetDeadband () {return (m_fDeadband);} void SetServerHandle (OPCHANDLE hServer) {m_hServer = hServer;} OPCHANDLE GetServerHandle () {return (m_hServer);} void SetValid (BOOL bValid) {m_bValid = bValid;} BOOL IsValid () {return (m_bValid);} void SetUpdateMethod (DWORD dwMethod) {m_dwUpdateMethod = dwMethod;} DWORD GetUpdateMethod () {return (m_dwUpdateMethod);} // flag accessor/manipulators void ForceDeletion (BOOL bSet) {m_bfFlags.bOnDeleteForceDeletion = bSet;} BOOL IsForceDeletion () {return (m_bfFlags.bOnDeleteForceDeletion);} // OPC Specifics void Initialize (LPUNKNOWN pUnk); void Uninitialize (bool bDelete = true); bool SetItemActiveState (CObArray &cItemList, DWORD cdwItems, bool bActive); void ReadSync (CObArray &cItemList, DWORD cdwItems, bool bDeviceRead, bool bPostMsg = true); void WriteSync (CObArray &cItemList, CStringArray &cValues, DWORD cdwItems); void ReadAsync10 (CObArray &cItemList, DWORD cdwItems, bool bDeviceRead); void RefreshAsync10 (bool bDeviceRead); void WriteAsync10 (CObArray &cItemList, CStringArray &cValues, DWORD cdwItems); void ReadAsync20 (CObArray &cItemList, DWORD cdwItems); void RefreshAsync20 (bool bDeviceRead); void WriteAsync20 (CObArray &cItemList, CStringArray &cValues, DWORD cdwItems); CHotOpcGroup* Clone (); void Start (); void ExportCsv (CStdioFile &csv); void ImportCsv (CStdioFile &csv, CObArray &cItemList, DWORD &cdwItems); // cut/copy/paste void Copy (CFixedSharedFile &sf); void Paste (CFixedSharedFile &sf); // parent server access CHotOpcServer* GetParentServer () {return (m_pServer);} // list management void SetPrev (CHotOpcGroup *pPrev) {m_pPrev = pPrev;} CHotOpcGroup* GetPrev () {return (m_pPrev);} void SetNext (CHotOpcGroup *pNext) {m_pNext = pNext;} CHotOpcGroup* GetNext () {return (m_pNext);} // item management void AddItems (CObArray &cItemList, DWORD dwCount, bool bLoadingProject = false); void RemoveItems (CObArray &cItemList, DWORD dwCount, bool bDelete = true); void RemoveAllItems (bool bDelete = true); CHotOpcItem* GetItemHead () {return (m_pItemHead);} DWORD GetItemCount () {return (m_cdwItems);} bool IsIGroupStateMgtSupported () {return (m_pIGroupState != NULL);} bool IsIPublicGroupStateMgtSupported () {return (m_pIPublicGroupState != NULL);} bool IsIItemMgtSupported () {return (m_pIItemMgt != NULL);} bool IsISyncIOSupported () {return (m_pISync != NULL);} bool IsIAsyncIOSupported () {return (m_pIAsync != NULL);} bool IsIDataObjectSupported () {return (m_pIDataObject != NULL);} bool IsIAsyncIO2Supported () {return (m_pIAsync2 != NULL);} bool IsIConnectionPointContainerSupported () {return (m_pIConnPtContainer != NULL);} IOPCItemMgt* GetIItemMgt () {return (m_pIItemMgt);} IOPCGroupStateMgt* GetIGroupStateMgt () {return (m_pIGroupState);} IOPCSyncIO* GetISyncIO () {return (m_pISync);} private: bool MapStringValToVariant (CString &strValue, VARIANT &vtVal, VARTYPE vtType); typedef enum _tagGETARRELEMRET { tElement = 0, tEndRow, tInvalid, tOverflow, tDone } GETARRELEMRET; GETARRELEMRET GetArrayElement (LPCTSTR szInBuff, int *pnStart, LPTSTR szOutBuff, int nBuffSize); bool MapStringValToArrayVariant (CString &strValue, VARIANT *pvtSrc, VARIANT *pvtDst); void AddItemToList (CHotOpcItem *pItem); void RemoveItemFromList (CHotOpcItem *pItem); private: // properties CString m_strName; // group name DWORD m_dwUpdateRate; // update rate in milliseconds LCID m_dwLanguageID; // language ID BOOL m_bActive; // active state long m_lBias; // time bias in minutes float m_fDeadband; // percent deadband OPCHANDLE m_hServer; // server handle for this group BOOL m_bValid; // TRUE if successfully added to the OPC server DWORD m_dwUpdateMethod; // update method used by this group (see globals.h) typedef struct _flags { DWORD bOnDeleteForceDeletion : 1; // TRUE if the server should force deletion of group even if references exists // DWORD bOnDeleteRemoveItems : 1; // TRUE if the client should remove items before remove group DWORD Reserved : 31; } FLAGS; FLAGS m_bfFlags; // OPC specifics IOPCGroupStateMgt *m_pIGroupState; IOPCPublicGroupStateMgt *m_pIPublicGroupState; IOPCItemMgt *m_pIItemMgt; IOPCSyncIO *m_pISync; IOPCAsyncIO *m_pIAsync; IDataObject *m_pIDataObject; IOPCAsyncIO2 *m_pIAsync2; IConnectionPointContainer *m_pIConnPtContainer; IKDataSink20 *m_pIDataSink20; DWORD m_dwCookieDataSink20; CKAdviseSink *m_pIAdviseSink; DWORD m_dwCookieRead; DWORD m_dwCookieWrite; // parent server CHotOpcServer *m_pServer; // list management CHotOpcGroup *m_pPrev; CHotOpcGroup *m_pNext; // item management CHotOpcItem *m_pItemHead; DWORD m_cdwItems; public: virtual void Serialize(CArchive& ar); }; // ************************************************************************** // CHotOpcItem 命令目标 /*--------------------------------------------- CHotOpcItem类 desc:... ----------------------------------------------*/ class CHotOpcItem : public CObject { public: // construction/destruction CHotOpcItem (CHotOpcGroup *pParent); ~CHotOpcItem (); public: // property accessor/manipulators void SetAccessPath (LPCTSTR strAccessPath) {m_strAccessPath = strAccessPath;} LPCTSTR GetAccessPath () {return (m_strAccessPath);} void SetActive (BOOL bActive) {m_bActive = bActive;} BOOL IsActive () {return (m_bActive);} void SetDataType (VARTYPE vtType) {m_vtDataType = vtType;} VARTYPE GetDataType () { if (m_vtValue.vt != VT_EMPTY) return (m_vtValue.vt); return (m_vtDataType); } void SetItemID (LPCTSTR strItemID) {m_strItemID = strItemID;} LPCTSTR GetItemID () {return (m_strItemID);} void SetServerHandle (OPCHANDLE hServer) {m_hServer = hServer;} OPCHANDLE GetServerHandle () {return (m_hServer);} void SetAccessRights (DWORD dwAccess) {m_dwAccessRights = dwAccess;} DWORD GetAccessRights () {return (m_dwAccessRights);} void SetValid (BOOL bValid) { m_bValid = bValid; if (!bValid) { m_wQuality = OPC_QUALITY_BAD_OUT_OF_SERVICE; m_cdwUpdates = 0; m_bTimeStamped = FALSE; VariantInit (&m_vtValue); } } BOOL IsValid () {return (m_bValid);} // data void UpdateData (VARIANT &vtVal, WORD wQuality); void UpdateData (VARIANT &vtVal, WORD wQuality, FILETIME &ftTimeStamp); void GetValue (CString &strValue); LPCTSTR GetQuality (); void GetTimeStamp (CString &strTimeStamp); DWORD GetUpdateCount (); // This can be dangerous!! VARIANT* GetValue () {return (&m_vtValue);} // cut/copy/paste void Copy (CFixedSharedFile &sf); void Paste (CFixedSharedFile &sf); // parent group access CHotOpcGroup* GetParentGroup () {return (m_pGroup);} // list management void SetPrev (CHotOpcItem *pPrev) {m_pPrev = pPrev;} CHotOpcItem* GetPrev () {return (m_pPrev);} void SetNext (CHotOpcItem *pNext) {m_pNext = pNext;} CHotOpcItem* GetNext () {return (m_pNext);} // GUI management void SetWParam (WPARAM wParam) {m_wParam = wParam;} WPARAM GetWParam () {return (m_wParam);} private: // properties CString m_strAccessPath; // access path CString m_strItemID; // fully qualified item ID BOOL m_bActive; // active state VARTYPE m_vtDataType; // server's canonical datatype DWORD m_dwAccessRights; // access rights OPCHANDLE m_hServer; // server handle for this item typedef struct _flags { DWORD Reserved : 32; } FLAGS; FLAGS m_bfFlags; BOOL m_bValid; // TRUE if successfully added to an OPC server BOOL m_bTimeStamped; // TRUE if the last update included a timestamp // data FILETIME m_ftTimeStamp; // timestamp attached to value WORD m_wQuality; // quality attached to value VARIANT m_vtValue; // current value DWORD m_cdwUpdates; // parent server CHotOpcGroup *m_pGroup; // list management CHotOpcItem *m_pPrev; CHotOpcItem *m_pNext; // threading CCriticalSection m_csDataLock; // GUI management WPARAM m_wParam; public: virtual void Serialize(CArchive& ar); }; // ************************************************************************** // CFixedSharedFile 命令目标 /*--------------------------------------------- CFixedSharedFile类 desc:... ----------------------------------------------*/ class CFixedSharedFile : public CSharedFile { public: CFixedSharedFile (int nGrowBy = 128) : CSharedFile (GMEM_DDESHARE | GMEM_MOVEABLE, nGrowBy) { } BYTE* GetBuffer () // Enhancement (must be used with care) { ASSERT (m_lpBuffer); return (m_lpBuffer); } HGLOBAL Detach () { ASSERT (m_hGlobalMemory != NULL); HGLOBAL hMem = m_hGlobalMemory; m_hGlobalMemory = NULL; // detach from global handle // This is the fix ::GlobalUnlock (hMem); // re-initialize the CMemFile parts too m_lpBuffer = NULL; m_nBufferSize = 0; return hMem; } // Enhancement to allow data to be transfered to the clipboard BOOL CopyToClipboard (UINT uFmt) { // Open the clipboard if (!::OpenClipboard (NULL)) { TRACE (_T("Shared Memory: Failed to open the clipboard\n")); return (false); } TRACE (_T("Copying %u bytes to the clipboard (uFmt == %u)\n"), GetLength (), uFmt); ASSERT (GetLength ()); // Clear out current contents ::EmptyClipboard (); // Stick the data in HANDLE hData = ::SetClipboardData (uFmt, Detach ()); ::CloseClipboard (); // Check for success if (!hData) { TRACE (_T("SetClipboardData () failed [OS Error == %u]\n"), GetLastError ()); ASSERT (FALSE); } return (hData != NULL); } protected: };