/*
*********************************************************************
*
*	The Essence of OLE
*
*	Source code sample
*
*	Copyright (c) 1996, Rolling Thunder Computing, Ipswich MA
*
*	e-mail: essence@rollthunder.com
*	CompuServe: 73540,3430
*	Web: http://www.rollthunder.com
*
*	File Name: MAINWIND.CPP
*
*	Purpose: Main window response function
*
*********************************************************************
*/


/*
*****************************************************************************
System header files
*****************************************************************************
*/

#include <windows.h>		    /* required for all Windows applications */


/*
*****************************************************************************
Application header files
*****************************************************************************
*/

#include "main.h"
#include "resource.h"

/*
*****************************************************************************
Function prototype files
*****************************************************************************
*/

/*
*****************************************************************************
Global Variables defined here
*****************************************************************************
*/

LPDATAOBJECT lpd = NULL ;
SYSTEMTIME st ;
                               
/*
*****************************************************************************
EXTERNS ofglobal variables defined in other files
*****************************************************************************
*/

extern HWND	hMainWnd ;
extern HINSTANCE hInst ;


/****************************************************************************

    FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)

    PURPOSE:  Processes messages


****************************************************************************/

GUID GUID_PersistTimeData ; 
UINT cfTimeData ;

long WINAPI MainWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{


	switch (message)
	{

		case WM_CREATE:
		{
/*
Register private clipboard formats
*/

			cfTimeData = RegisterClipboardFormat ("TimeDataObject") ;
/*
Read class ID from registry
*/
			CLSIDFromProgID(L"EssenceOfCOM.PersistStream", &GUID_PersistTimeData) ;

			return 0 ;
		}

/*
WM_COMMAND is a command from the application menu
*/

		case WM_COMMAND:
		{
                    
			switch (wParam)
			{
				case ID_DATAOBJECT_CREATE:
				{
					HRESULT hr ;

				  	DWORD InitTickCount = GetTickCount ( ) ;

					hr = CoCreateInstance (
						GUID_PersistTimeData,
						NULL,
						CLSCTX_LOCAL_SERVER,
						IID_IDataObject,
						(void **) &lpd) ;

					InvalidateRect (hWnd, NULL, TRUE) ;

					if (!SUCCEEDED(hr))
					{
						MessageBox (hWnd, "Couldn't create object", "Error", MB_ICONSTOP) ;
					}
					return 0 ;
				}


				case ID_DATAOBJECT_RELEASE:
				{
					if (lpd)
					{
						lpd->Release( ) ;
						lpd = NULL ;
					}

					InvalidateRect (hWnd, NULL, TRUE) ;
					return 0 ;
				}

				case ID_DATAOBJECT_GETDATA:
				{
					if (lpd)
					{
						FORMATETC fe ;
						STGMEDIUM stm ;

						fe.cfFormat = cfTimeData ;
						fe.ptd = NULL ;
						fe.dwAspect = DVASPECT_CONTENT ;
						fe.lindex = -1 ;
						fe.tymed = TYMED_HGLOBAL ;

					 	if (SUCCEEDED(lpd->GetData (&fe, &stm)))
						{
							InvalidateRect (hWnd, NULL, TRUE) ;

							char *cp ;
							cp = (char *)GlobalLock (stm.hGlobal) ;
							memmove (&st, cp, sizeof (st)) ;
							GlobalUnlock (stm.hGlobal) ;
							ReleaseStgMedium (&stm) ;
							InvalidateRect (hWnd, NULL, TRUE) ;
						}
					}

					return 0 ;
				}



				case ID_DATAOBJECT_EXIT:
				{
					SendMessage (hWnd, WM_CLOSE, 0, 0L) ;        
					return 0 ;
				}
				case ID_STREAM_SAVETOSTREAM:
				{

					HRESULT hr ;

/*
Query the data object for the IPersistStream interfaceto see if it is
capable of saving to a stream.
*/
					
					IPersistStream *pPerStream ;

					hr = lpd->QueryInterface (IID_IPersistStream, (LPVOID*) &pPerStream) ;

					if (!SUCCEEDED(hr))
					{
						MessageBox (NULL, "Data object does not support IPersistStream",
							"Error", MB_ICONSTOP) ;
						return 0 ;
					}

/*
Create storage file, clobbering any previous version.
*/

					IStorage *pStor ;

					hr = StgCreateDocfile (L"adata4.ips", 
						STGM_CREATE | STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
						0, 
						&pStor) ;

					if (!SUCCEEDED(hr))
					{
						MessageBox (NULL, "Could not create storage file", "Error", MB_ICONSTOP) ;
						pPerStream->Release ( ) ;
						return 0 ;
					}

/*
Create a stream within the storage file.
*/
					IStream *pStream ;

					hr = pStor->CreateStream (L"Data",
						STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 
 						0, 0, &pStream) ;

					if (!SUCCEEDED(hr))
					{
						MessageBox (NULL, "Could not open stream", "Error", MB_ICONSTOP) ;
						pStor->Release ( ) ;
						pPerStream->Release ( ) ;
					}

/*
Ask the object for its class ID.  Write that into the stream.
*/
					CLSID clsid ;

					pPerStream->GetClassID (&clsid) ;
					
					WriteClassStm (pStream, clsid) ;

/*
Tell the object to save its data into the stream.
*/

					pPerStream->Save (pStream, TRUE) ;

/*
Release interface pointer when done.
*/

					pPerStream->Release ( ) ;
					pStream->Release ( ) ;
					pStor->Release ( ) ;

					return 0 ;
				}

				case ID_STREAM_LOADFROMSTREAM:
				{
/*
Try to open our storage file, and then the stream within it that
holds the object data.  Fail if not possible.
*/
					HRESULT hr ;
						
					IStorage *pStor ;

					hr = StgOpenStorage (L"adata4.ips", NULL, 
						STGM_READ | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
						NULL, 0, 
						&pStor) ;

					if (!SUCCEEDED(hr))
					{
						MessageBox (NULL, "Could not open file adata4.ips", "Error", MB_ICONSTOP) ;
						return 0 ;
					}


					IStream *pStream ;

					hr = pStor->OpenStream (L"Data", 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream) ;

					if (!SUCCEEDED(hr))
					{
						MessageBox (NULL, "Could not open stream", "Error", MB_ICONSTOP) ;
						pStor->Release (  );
						return 0 ;
					}

/*
Read the class ID from the stream.  Attempt to create an object based
on it.
*/

					CLSID clsid ;

					ReadClassStm (pStream, &clsid) ;
					
					hr = CoCreateInstance (clsid, NULL, CLSCTX_LOCAL_SERVER, 
						IID_IDataObject, (LPVOID *)&lpd) ;

					if (!SUCCEEDED(hr))
					{
						MessageBox (NULL, "Couldn't create object", "Error", MB_ICONSTOP) ;
						pStream->Release ( ) ;
						pStor->Release ( ) ;
						return 0 ;
					}

/*
Query for the IPersistStream interface.  If found, tell object to load
its data from the stream.
*/

					IPersistStream *pPerStream ;

					hr = lpd->QueryInterface (IID_IPersistStream, (LPVOID*) &pPerStream) ;

					if (!SUCCEEDED(hr))
					{
						MessageBox (NULL, "Data object does not support IPersistStream",
							"Error", MB_ICONSTOP) ;
						pStream->Release ( ) ;
						pStor->Release ( ) ;
						return 0 ;
					}

					pPerStream->Load (pStream) ;

/*
Get the object's data and display on the screen
*/
					SendMessage (hWnd, WM_COMMAND, ID_DATAOBJECT_GETDATA, 0) ;

/*
Release	interface pointers when done.
*/
					pPerStream->Release ( ) ;
					pStream->Release ( ) ;
					pStor->Release ( ) ;

					return 0 ;
				}
				
			}

			return 0 ;
		}


		case WM_INITMENU:
		{
			HMENU hMenu ;

			hMenu = GetMenu (hWnd) ;

			if (lpd)
			{
				EnableMenuItem (hMenu, ID_DATAOBJECT_CREATE, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_STREAM_LOADFROMSTREAM, MF_GRAYED) ;
				
				EnableMenuItem (hMenu, ID_DATAOBJECT_GETDATA, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_DATAOBJECT_RELEASE, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_STREAM_SAVETOSTREAM, MF_ENABLED) ;

			}
			else
			{
				EnableMenuItem (hMenu, ID_DATAOBJECT_CREATE, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_DATAOBJECT_GETDATA, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_DATAOBJECT_RELEASE, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_STREAM_SAVETOSTREAM, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_STREAM_LOADFROMSTREAM, MF_ENABLED) ;
			}

			return 0 ;
		}


/*
Shutdown time.  
*/

		case WM_CLOSE:
		{
			DestroyWindow (hWnd) ;
			return 0 ;
		}

	
		case WM_DESTROY:
		{           
		  	PostQuitMessage (0) ;
		  	return 0 ;
		}
		
		case WM_PAINT:
		{
			PAINTSTRUCT ps ;
			HDC hDC ;
			char out [256] ;
			int length ;

			
			hDC = BeginPaint (hWnd, &ps) ;
			
			if (!lpd)
			{
				TextOut (hDC, 0, 0, "<no object>", 11) ;
			}
			else
			{
				length = wsprintf (out, "%2.2d:%2.2d:%2.2d", st.wHour, st.wMinute, st.wSecond) ;
				TextOut (hDC, 0, 0, out, length) ;
			} 

			EndPaint (hWnd, &ps) ;
			return 0 ;
		}
	}
	return DefWindowProc(hWnd, message, wParam, lParam) ;
}


