/*
*********************************************************************
*
*	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 */
#include <afxres.h>

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

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

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

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

BOOL bTextChanged = FALSE, bSummaryChanged = FALSE, bUnnamedFile = TRUE ;
LPSTORAGE pRootStg  ;

CLSID MyCLSID =  { 0x332DACA0L, 0x8AB6, 0x101B, {0x89, 0x7A, 0x00, 0x60, 0x8C, 0x86, 0xB8, 0x9C } };

HWND hEdit ;

WCHAR WideFileName [256] = L"delete.me";

/*
*****************************************************************************
EXTERNS ofglobal variables defined in other files
*****************************************************************************
*/

extern HWND	hMainWnd ;
extern HINSTANCE hInst ;


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

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

    PURPOSE:  Processes messages


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

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


	switch (message)
	{

		case WM_CREATE:
		{   
			HRESULT hr ;
/*
Create edit control for user to enter text.
*/
			hEdit = CreateWindow ("edit", "", 
				WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL | WS_BORDER ,
				0, 0, 0, 0, 
				hWnd, (HMENU) IDC_EDIT, hInst, NULL) ;
		
			SetFocus (hEdit) ;
/*
Create empty file for user to operate with. Set up its internal structure.
*/
			hr = StgCreateDocfile (NULL, 
				STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | 
				STGM_TRANSACTED | STGM_DELETEONRELEASE, 
				0, &pRootStg) ;

			WriteNewStorageStructure (pRootStg) ;

			return 0 ;
		}
		
       			
/*
WM_COMMAND is a command from the application menu
*/

		case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{
	
/*
User picked "File -- Open
*/
				case ID_FILE_OPEN:
				{
				
					OPENFILENAME of ;
					char FileTitle [128] ;

					ZeroMemory (&of, sizeof(of)) ;
					
					of.lStructSize = sizeof (of) ;
					of.hwndOwner = hWnd ;
					of.lpstrFileTitle = FileTitle ;
					of.nMaxFileTitle = sizeof (FileTitle) ;
					of.lpstrFilter = "All filess\0*.*\0" ;

					if (GetOpenFileName (&of)) 
					{
/*
If necessary, ask user if he wants to save changes. If so, then do it.
*/
						if (bTextChanged || bSummaryChanged)
						{
							UINT result ;

							result = MessageBox (hWnd, "Save Changes ?", 
								"Ole Lab", MB_YESNOCANCEL | MB_ICONQUESTION) ;

							if (result == IDCANCEL)
							{
								return 0;
							}
							else if (result == IDYES)
							{
								if (SendMessage (hWnd, WM_COMMAND, ID_FILE_SAVE, 0) != 0)
								{
									return 0 ;
								}
							}
						}

/*
If a file is currently open, release it.
*/
						if (pRootStg)
						{
							pRootStg->Release( ) ;
						}

/*
Convert dialog box name to wide char.  
*/
						MultiByteToWideChar (CP_ACP, 0, FileTitle, -1, WideFileName, 80) ;

/*
Call file open function.  If successful, modify title bar and reset flags.
*/
						if (OpenFileByName (WideFileName, &pRootStg))
						{
							char out [256] ;
							wsprintf (out, "Essence of OLE strucstr.exe - %s", FileTitle) ;
							SetWindowText (hWnd, out) ;
							bSummaryChanged = bTextChanged = bUnnamedFile = FALSE ;
						}
					}

					return 0 ;

				}
				
/*
Save our data to a compound file.  We have to write the text from the
edit control into a stream ourselves.  Then the Commit( ) method will physically write that
change, and any other changes made to any streams or substorages below
the main storage, to disk.  In this app, that means the Author and Title
streams in the Summary Info substorage.
*/
				case ID_FILE_SAVE:
				{
					if (bUnnamedFile)
					{
						return SendMessage (hWnd, WM_COMMAND, ID_FILE_SAVEAS, 0) ;
					}

					LPSTREAM pStream ;
					char buf [4096] ;
					int length ;

				 	pRootStg->OpenStream (L"DisplayText",  NULL, 
						STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL,
						&pStream) ;

					length = GetWindowText (hEdit, buf, sizeof(buf)) + 1 ;
					pStream->Write (buf, length, NULL) ;
					pStream->Release ( ) ;


 					pRootStg->Commit(STGC_DEFAULT) ;

					bSummaryChanged = bTextChanged = FALSE ;
					return 0 ;
				}


/*
User picked "File -- Save As" from the main menu.
*/
				
				case ID_FILE_SAVEAS:
				{
					OPENFILENAME of ;
					char FileTitle [128] ;

					ZeroMemory (&of, sizeof(of)) ;
					
					of.lStructSize = sizeof (of) ;
					of.hwndOwner = hWnd ;
					of.lpstrFileTitle = FileTitle ;
					of.nMaxFileTitle = sizeof (FileTitle) ;
					of.lpstrFilter = "All Files\0*.*\0" ;

					if (GetSaveFileName (&of)) 
					{
						IStorage * pNewStg ;
						HRESULT hr ;
						char out [128] ;


						MultiByteToWideChar (CP_ACP, 0, FileTitle, -1, WideFileName, 80) ; 

/*
Create new storage for saved contents, with name specified by dialog box.
*/

						hr = StgCreateDocfile (WideFileName, 
							STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_CREATE, 
							0, &pNewStg) ;

/*						
Copy the current main storage's contents into the new one.  Then release
the current main storage and make the newly-created storage the main
document storage
*/
						hr = pRootStg->CopyTo (NULL, NULL, NULL, pNewStg) ;
						pRootStg->Release ( ) ;

						pRootStg = pNewStg ;
						bUnnamedFile = FALSE ;
						SendMessage (hWnd, WM_COMMAND, ID_FILE_SAVE, 0) ;
						
/*
Update title bar
*/
						wsprintf (out, "Essence of OLE strucstr.exe - %s", FileTitle) ;
						SetWindowText (hWnd, out) ;
						bSummaryChanged = bTextChanged = FALSE ;
						return 0 ;
					}
					else
					{
						return -1 ;
					}
				
				}

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


				case ID_FILE_SUMMARYINFO:
				{
				 	if (DialogBoxParam (hInst, MAKEINTRESOURCE (IDD_DIALOG2), 
						hWnd, (DLGPROC) SummaryDlgProc, (LPARAM)pRootStg))
					{
						bSummaryChanged = TRUE ;
					}
					return 0 ;
				}

/*
Revert to last saved version, discarding changes
*/
				case ID_STORAGE_REVERT:
				{
					if (bSummaryChanged || bTextChanged)
					{
						UINT result ;

						result = MessageBox (hWnd, "Discard Changes ?", 
							"Revert", MB_YESNO | MB_ICONQUESTION) ;

						if (result == IDYES)
						{
/*
use the IStorage::Revert( ) method to roll back the uncomitted changes
made to any element contained at any level within the main storage.  In 
this app, that means the Author and Title streams in the Summary Info 
substorage	
*/
							HRESULT hr ;

							pRootStg->Revert( ) ;
							pRootStg->Release ( ) ;

							if (bUnnamedFile)
							{
								hr = StgCreateDocfile (NULL, 
									STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | 
									STGM_TRANSACTED | STGM_DELETEONRELEASE, 
									0, &pRootStg) ;
								WriteNewStorageStructure (pRootStg) ;
							}
							else
							{
								hr = StgOpenStorage (WideFileName,  NULL, 
									STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 
									NULL, 0, &pRootStg) ;
							}


/*
is kept current in memory and written to 
a stream only when it is saved,see case ID_FILE_SAVE above, so it has
to be reloaded here.
*/
							if (bTextChanged)
							{
								LPSTREAM pStream ;  
								DWORD nActual ;
								char buf [4096] ;

					 			pRootStg->OpenStream (L"DisplayText",  NULL, 
									STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL,
									&pStream) ;
								pStream->Read (buf, sizeof (buf), &nActual) ;
								buf [nActual] = 0x00 ;
								SetWindowText (hEdit, buf) ;

								pStream->Release ( ) ;
							}

							bTextChanged = bSummaryChanged = FALSE ;
						}
					}
					
					return 0 ;
				}

				case ID_STORAGE_ENUMERATE:
				{
					DialogBoxParam (hInst, MAKEINTRESOURCE (IDD_DIALOG3), 
						hWnd, (DLGPROC) EnumElementsDlgProc,
						(LPARAM) pRootStg) ;
					return 0 ;
				}

/*
Open a new temporary storage.  Copy the main storage to it, which 
de-fragments the file.  Then copy the new temporary storage back to the 
original one.  Hey, Presto !
*/

				case ID_STORAGE_DEFRAGMENT:
				{
					LPSTORAGE pTempStg ;

					if (bTextChanged || bSummaryChanged)
					{
						UINT result = MessageBox (hWnd, "Save Changes ?", "Defragment",
							MB_YESNOCANCEL | MB_ICONEXCLAMATION) ;
						
						if (result == IDCANCEL)
						{
							return 0 ;
						}
						else if (result == IDYES)
						{
							SendMessage (hWnd, WM_COMMAND, ID_FILE_SAVE, 0) ;
						}
					}


							
					StgCreateDocfile (NULL, 
						STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | 
						STGM_DELETEONRELEASE, 
						0, &pTempStg) ;

					pRootStg->CopyTo (NULL, NULL, NULL, pTempStg) ;
					pTempStg->CopyTo (NULL, NULL, NULL, pRootStg) ;
					pRootStg->Commit(STGC_DEFAULT) ;
					pTempStg->Release( ) ;

					return 0 ;
				}

				case IDC_EDIT:
				{
					if (HIWORD(wParam) == EN_CHANGE)
					{
						bTextChanged = TRUE ;
					}
					return 0 ;
				}
			}

			return 0 ;
		}


/*
Shutdown time.  Revoke the drag and drop operation and Release( ) the drop
target object.  Then uninitialize the OLE libraries.
*/

		case WM_CLOSE:
		{
			if (bTextChanged || bSummaryChanged)
			{
				UINT result ;

				result = MessageBox (hWnd, "Save Changes ?", 
					"Ole Lab", MB_YESNOCANCEL | MB_ICONQUESTION) ;

				if (result == IDCANCEL)
				{
					return 0;
				}
				else if (result == IDYES)
				{
					if (SendMessage (hWnd, WM_COMMAND, ID_FILE_SAVE, 0) != 0)
					{
						return 0 ;
					}
				}
			}

/*
Release whatever main document storage we have
*/
			if (pRootStg)
			{
				pRootStg->Release( ) ;
			}

			DestroyWindow (hWnd) ;
			return 0 ;
			
		}


		case WM_SIZE:
		{
			MoveWindow (hEdit, 5, 5, LOWORD(lParam) - 10, HIWORD(lParam)-10, TRUE) ;
			return 0 ;
		}

		case WM_DESTROY:
		{           
		  	PostQuitMessage (0) ;
		  	return 0 ;
		}
	}
       
	return DefWindowProc(hWnd, message, wParam, lParam) ;
	
}


