FORM.CPP

// --form.cpp----------------------------------------------------------------- 
//
// Implementation of the FRM class
//
// Implements a simple form that holds information about a software
// testing/development tool. This form can be installed in
// a public folder, and then forms of this type can be placed in
// the public folder to create a database of software tools.
// Th form holds the following information:
//
// * A topic, giving a brief description of the tool, which
// appears as the subject in the folder list.
// * Name of the tool
// * The platform the tool runs on
// * The type of tool
// * The Operating System the tool runs under
// * Who developed the tool
// * The location of the tool
// * An introduction, giving a longer description of the tool.
//
//
// Copyright (C) Microsoft Corp. 1986-1996. All Rights Reserved.
// ---------------------------------------------------------------------------

#include "stdafx.h"
#include "tool.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

#define new DEBUG_NEW

#include <ole2.h>
DEFINE_GUID(CLSID_MyFormsClsId, 0x861E4010, 0x5030, 0xFEDC, 0x99, 0x12, 0x00, 0x0a, 0x00, 0x38, 0x90, 0x1b);

#include "formdata.h"
#include "form.h"
#include "tooldoc.h"
#include "toolform.h"

HINSTANCE hinstOle = NULL;
HINSTANCE hinstMapi = NULL;

#ifdef WIN16
LPFNISEQUALGUID lpfnIsEqualGUID;
#endif
LPFNCOREGISTERCLASSOBJECT lpfnCoRegisterClassObject;
LPFNHRQUERYALLROWS lpfnHrQueryAllRows ;
LPFNMAPIFREEBUFFER lpfnMAPIFreeBuffer ;
LPFNMAPIINITIALIZE lpfnMAPIInitialize ;
LPFNMAPIUNINITIALIZE lpfnMAPIUninitialize ;
FRMFAC * g_pfrmfac = NULL;


//$--HrStartOleAndRegisterClassFactory----------------------------------------
//
// Purpose:
// Initialize OLE, MAPI, and the Forms Interface
// Should be called from WinMain() or InitApplication() in an SDI app
//
// This function LoadLibraries the neccessary DLLs rather than
// linking with them. This permits the form to run as a stand-
// alone executable even when MAPI and OLE are not installed.
//
// Returns:
// HRESULT
// ---------------------------------------------------------------------------
HRESULT HrStartOleAndRegisterClassFactory(void)
{
HRESULT hr = NOERROR;

// ----- LoadLibrary the essentials
hinstOle = LoadLibrary(szOleDll);
hinstMapi = LoadLibrary(szMapiDll);
#ifdef WIN16
if (hinstOle < HINSTANCE_ERROR) hinstOle = 0;
if (hinstMapi < HINSTANCE_ERROR) hinstMapi = 0;
#endif
if (0 == hinstOle || 0 == hinstMapi)
{
return ResultFromScode(E_FAIL);
}


// ----- Setup a few function pointers
lpfnCoRegisterClassObject = (LPFNCOREGISTERCLASSOBJECT) GetProcAddress(hinstOle, "CoRegisterClassObject");
lpfnHrQueryAllRows = (LPFNHRQUERYALLROWS ) GetProcAddress(hinstMapi,"HrQueryAllRows");
if (NULL == lpfnHrQueryAllRows)
{
lpfnHrQueryAllRows = (LPFNHRQUERYALLROWS ) GetProcAddress(hinstMapi,"HrQueryAllRows@24");
}
#ifndef WIN32
lpfnIsEqualGUID = (LPFNISEQUALGUID ) GetProcAddress(hinstOle, "IsEqualGUID");
#endif
lpfnMAPIFreeBuffer = (LPFNMAPIFREEBUFFER ) GetProcAddress(hinstMapi,"MAPIFreeBuffer");
lpfnMAPIInitialize = (LPFNMAPIINITIALIZE ) GetProcAddress(hinstMapi,"MAPIInitialize");
lpfnMAPIUninitialize = (LPFNMAPIUNINITIALIZE ) GetProcAddress(hinstMapi,"MAPIUninitialize");

ASSERT(lpfnCoRegisterClassObject);
ASSERT(lpfnHrQueryAllRows);
ASSERT(lpfnMAPIFreeBuffer);
ASSERT(lpfnMAPIInitialize);
ASSERT(lpfnMAPIUninitialize);

if (NULL == lpfnCoRegisterClassObject ||
NULL == lpfnHrQueryAllRows ||
NULL == lpfnMAPIFreeBuffer ||
NULL == lpfnMAPIInitialize ||
NULL == lpfnMAPIUninitialize )
{
return ResultFromScode(E_FAIL);
}

// ----- Initialize MAPI
hr = lpfnMAPIInitialize(NULL);

if (FAILED(hr))
{
return hr;
}

// ----- Allocate Memory for our class factory
TRY
{
g_pfrmfac = new FRMFAC;
}
CATCH(CMemoryException, e)
{
hr = ResultFromScode(E_OUTOFMEMORY);
return hr;
}
END_CATCH

// ----- Register our class object(s)
DWORD dwRegMyForm = 0;
hr = lpfnCoRegisterClassObject(CLSID_MyFormsClsId, (LPUNKNOWN)g_pfrmfac,
CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE,
&dwRegMyForm); /* switch singleuse to multipleuse if you are an MDI app */

return hr;
}


//$--HrStopForms--------------------------------------------------------------
//
// Purpose:
// UnInitialize OLE, MAPI, and the Forms Interface
//
// Returns:
// HRESULT == 0
// ---------------------------------------------------------------------------
HRESULT HrStopForms(void)
{
HRESULT hr = ResultFromScode(S_OK);

if (g_pfrmfac)
delete g_pfrmfac;

if (lpfnMAPIUninitialize)
lpfnMAPIUninitialize();

FreeLibrary(hinstOle);
FreeLibrary(hinstMapi);

return hr;
}

// Tool form specific methods follow ///////////////////////////


//$--FRM::FRM-----------------------------------------------------------------
//
// Purpose:
// Initialize or new form object
//
//----------------------------------------------------------------------------
FRM::FRM(REFCLSID clsid)
{
LONG i;

m_cRef = 1;
m_clsid = clsid;

m_pMessage = NULL;
m_pMessageSite = NULL;
m_pSession = NULL;

m_pFormMgr = NULL;
m_pFormInfo = NULL;

m_fDirty = FALSE;

for (i=0; i<MAX_ADVISE; i++)
{
m_aAdvisePtrs[i] = NULL;
m_afAdvisee[i] = 0;
}
}


//$--FRM::~FRM----------------------------------------------------------------
//
// Purpose:
// Destroy our form object
//
//----------------------------------------------------------------------------
FRM::~FRM()
{
ASSERT(0 == m_cRef);
ASSERT(NULL == m_pMessage);
ASSERT(NULL == m_pMessageSite);
ASSERT(NULL == m_pSession);
}


//$--FRM::SendForm------------------------------------------------------------
//
//
// Purpose:
// Have the message site send us
// (also tries to send the message using mapi if message site fails)
//
// Returns:
// HRESULT Error status.
//----------------------------------------------------------------------------
HRESULT FRM::SendForm(VOID)
{
HRESULT hr = S_OK;

ASSERT(m_cRef > 0);
ASSERT(m_pMessageSite);
ASSERT(m_pMessage);

// ----- Submit message
hr = m_pMessageSite->SubmitMessage(0);

if (FAILED(hr))
{
return hr;
}
// ----- advise everyone of what we just did
ADVISE(OnSubmitted);

return hr;
}


//$--FRM::LaunchReplyMessage--------------------------------------------------
//
// Purpose:
// Construct a reply to PR_SENDER* (note: ignoring sent representing)
// Display any form user interface on the existing form
//
// Returns:
// HRESULT Error status.
//----------------------------------------------------------------------------
HRESULT
FRM::LaunchReplyMessage(ULONG ulhwndParent) // Parent window
{
ULONG itaga;
ADRLIST al = {1,0}; /* our adrlist will have exactly one entry */
HRESULT hr = S_OK;
LPMAPIMESSAGESITE pNewMessageSite;
LPMAPIVIEWCONTEXT pNewMapiViewContext;
LPMESSAGE pNewMessage;

SizedSPropTagArray(6,tagaSender) =
{ 6,
{ PR_RECIPIENT_TYPE,
PR_SENDER_NAME,
PR_SENDER_ADDRTYPE,
PR_SENDER_ENTRYID,
PR_SENDER_EMAIL_ADDRESS,
PR_SENDER_SEARCH_KEY } };
SizedSPropTagArray(6,tagaRepliee) =
{ 6,
{ PR_RECIPIENT_TYPE,
PR_DISPLAY_NAME,
PR_ADDRTYPE,
PR_ENTRYID,
PR_EMAIL_ADDRESS,
PR_SEARCH_KEY
} };
static SizedSPropTagArray(26,tagaRemoveFromNewReply) =
{ 26,
{ // Stuff you would typically want to remove on reply
PR_MESSAGE_FLAGS, // Want unsent compose note
PR_MESSAGE_RECIPIENTS, // Will generate new recip list
PR_SENDER_ENTRYID, // Clear sender/recipient info
PR_SENDER_NAME, //
PR_RECEIVED_BY_ENTRYID, //
PR_RECEIVED_BY_NAME, //
PR_SENT_REPRESENTING_ENTRYID, // Clear delegate access stuff
PR_SENT_REPRESENTING_NAME, //
PR_SENT_REPRESENTING_ADDRTYPE, // 10961
PR_SENT_REPRESENTING_EMAIL_ADDRESS,
PR_RCVD_REPRESENTING_ENTRYID, //
PR_RCVD_REPRESENTING_NAME, //
PR_READ_RECEIPT_ENTRYID, // Clear destination overrides
PR_REPORT_ENTRYID, //
PR_REPLY_RECIPIENT_ENTRIES, //
PR_REPLY_RECIPIENT_NAMES, //
PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED, // Clear delivery receipt
PR_READ_RECEIPT_REQUESTED, // Clear read receipt
PR_CLIENT_SUBMIT_TIME, // Clear submit time
PR_MESSAGE_ATTACHMENTS, // Drop attachments on reply
PR_ORIGINAL_AUTHOR_ENTRYID, // Keep original author information
PR_ORIGINAL_AUTHOR_NAME, // on forwards
PR_ORIGINAL_SUBMIT_TIME, // Keep original time on forwards
PR_IMPORTANCE, // Lose importance on reply
PR_PRIORITY, // Lose priority on reply
PR_SENSITIVITY // Lose sensitivity on reply
} };

ASSERT(m_cRef > 0);
ASSERT(m_pMessageSite);
ASSERT(m_pSession);
ASSERT(m_pMessage);

// ----- Create the reply message
hr = m_pMessageSite->NewMessage(0,NULL,
this, &pNewMessage,&pNewMessageSite,&pNewMapiViewContext);
if (FAILED(hr))
{
return hr;
}

ASSERT(pNewMessage);
ASSERT(pNewMessageSite);
ASSERT(pNewMapiViewContext);

// ----- Copy current message to new message
hr = m_pMessage->CopyTo(0, NULL, (LPSPropTagArray)&tagaRemoveFromNewReply, 0, NULL,
(LPIID) &IID_IMessage, pNewMessage, 0, NULL);
if (FAILED(hr))
{
return hr;
}

// ----- who sent this to us?
hr = m_pMessage->GetProps((LPSPropTagArray) &tagaSender, 0, &al.aEntries[0].cValues, &al.aEntries[0].rgPropVals);

ASSERT(ResultFromScode(MAPI_W_ERRORS_RETURNED) == hr);

// ----- Make the sender the recipient
if (al.aEntries && al.aEntries[0].rgPropVals)
{
al.aEntries[0].rgPropVals[0].ulPropTag = PR_RECIPIENT_TYPE;
al.aEntries[0].rgPropVals[0].Value.ul = MAPI_TO;
}
else
{
return ResultFromScode(E_FAIL);
}

// ----- Set our new recipients properties to their expected property ids
itaga = 1;

for (itaga = 1; itaga < tagaRepliee.cValues; itaga++)
{
al.aEntries[0].rgPropVals[itaga].ulPropTag =
PROP_TAG(PROP_TYPE(al.aEntries[0].rgPropVals[itaga].ulPropTag),
PROP_ID(tagaRepliee.aulPropTag[itaga]));


ASSERT(SUCCEEDED(al.aEntries[0].rgPropVals[itaga].Value.ul));
}

// ----- Save out addresses
ASSERT(1 == al.cEntries);
hr = pNewMessage->ModifyRecipients(0, &al);
if (FAILED(hr) )
{
return hr;
}

// ----- Call Load (this makes the current form the new form)
hr = Load(pNewMessageSite,pNewMessage,0,MSGFLAG_UNSENT);
if (FAILED(hr))
{
return hr;
}


// ----- Call DoVerb So we can see the reply form
hr = DoVerb(OLEIVERB_PRIMARY,NULL,ulhwndParent,NULL);
if (FAILED(hr))
{
return hr;
}

// ----- release stuff
pNewMessage->Release();
pNewMessageSite->Release();
pNewMapiViewContext->Release();
lpfnMAPIFreeBuffer(al.aEntries[0].rgPropVals);

return hr;

}

//$--FRM::GetFormData---------------------------------------------------------
//
// Purpose:
// Allows anyone to query the form for it's current data
//
// Returns:
// void
//----------------------------------------------------------------------------
VOID FRM::GetFormData(CFormData& theLocalFormData)
{
ASSERT(m_cRef > 0);

theLocalFormData = m_theFormData;
}


//$--FRM::SetFormData---------------------------------------------------------
//
//
// Purpose:
// Allows anyone to set the forms current data members
//
// Returns:
// void
//----------------------------------------------------------------------------
VOID FRM::SetFormData(const CFormData& theLocalFormData)
{
ASSERT(m_cRef > 0);

m_theFormData = theLocalFormData;

m_fDirty = TRUE;
}


//$--FRM::AddressForm---------------------------------------------------------
//
// Purpose:
// Add the address "Tools" to the "To:" list for the form.
//
// Returns:
// HRESULT Error Status.
//----------------------------------------------------------------------------
HRESULT
FRM::AddressForm(
HWND hwnd, // parent
BOOL fDontShowIfRecipsExist) // true if no user interface should
// be presented when recipients are
// already present
{
LPADRBOOKpAdrBook= NULL;
ULONGcbeid= 0;
LPENTRYIDlpeid= NULL;
ULONGulUIParam = (ULONG) (UINT) hwnd;
HRESULThr = S_OK;
LPADRLISTpal = NULL;
LPSPropValuergAdrProps= NULL;

ASSERT(m_cRef > 0);
ASSERT(m_pMessageSite);
ASSERT(m_pSession);
ASSERT(m_pMessage);

// ----- remember address book from the session
hr = m_pSession->OpenAddressBook(0, NULL, AB_NO_DIALOG, &pAdrBook);
if (FAILED(hr))
{
goto cleanup;
}

hr = MAPIAllocateBuffer(CbNewADRLIST(1), (LPVOID FAR *)&pal);
if (FAILED(hr))
{
goto cleanup;
}

pal->cEntries = 1;

pal->aEntries[0].ulReserved1 = 0;
pal->aEntries[0].cValues = 2;
pal->aEntries[0].rgPropVals = NULL;

// Allocate memory for the recipient properties
hr = MAPIAllocateBuffer(2*sizeof(SPropValue), (LPVOID *)&rgAdrProps);

if (FAILED(hr))
{
printf("MAPIAllocateBuffer() failed\n");
goto cleanup;
}

pal->aEntries[0].rgPropVals = rgAdrProps;

rgAdrProps[0].ulPropTag = PR_DISPLAY_NAME;
rgAdrProps[0].Value.LPSZ = "Tools";

rgAdrProps[1].ulPropTag = PR_RECIPIENT_TYPE;
rgAdrProps[1].Value.l = MAPI_TO;

hr = pAdrBook->ResolveName(0,
MAPI_DIALOG,
NULL,
pal);

if (FAILED(hr))
{
goto cleanup;
}

hr = m_pMessage->ModifyRecipients(MODRECIP_ADD, pal);

// ----- Release the address book, adrlist, and clean up
cleanup:
if (pAdrBook)
{
pAdrBook->Release();
}
if (pal)
{
lpfnMAPIFreeBuffer(pal->aEntries[0].rgPropVals);
lpfnMAPIFreeBuffer(pal);
}

return hr;
}


//$--FRM::Remember------------------------------------------------------------
//
// Purpose:
// Store and addref the message site, the message, and the session
// for later use
//
// Returns:
// HRESULT Error Status.
//----------------------------------------------------------------------------
HRESULT FRM::Remember(LPMAPIMESSAGESITE pmsite, LPMESSAGE pmsg)
{
HRESULT hr;

ASSERT(m_cRef > 0);
ASSERT(pmsite);
ASSERT(pmsg);

// ----- remember our message site object
if(!m_pMessageSite)
{
m_pMessageSite = pmsite;
m_pMessageSite->AddRef();
}

// ----- remember our message
if(!m_pMessage)
{
m_pMessage = pmsg;
m_pMessage->AddRef();
}

// ----- remember mapi session
if(!m_pSession)
{
hr = m_pMessageSite->GetSession(&m_pSession);
}

return hr;

}


//$--FRM::Forget--------------------------------------------------------------
//
// Purpose:
// Release the message site, the message, and the session
//
// Returns:
// HRESULT Error Status.
//----------------------------------------------------------------------------
HRESULT FRM::Forget(VOID)
{
if (m_pMessage)
m_pMessage->Release();
if (m_pMessageSite)
m_pMessageSite->Release();
if (m_pSession)
m_pSession->Release();

m_pMessage = NULL;
m_pMessageSite = NULL;
m_pSession = NULL;

return NOERROR;
}

//$--FRM::ShowCurrentMessage--------------------------------------------------
//
// Purpose:
// Display any form user interface on a form
//
// Returns:
// HRESULT Error status.
//----------------------------------------------------------------------------
HRESULT FRM::ShowCurrentMessage(ULONG ulhwndParent) // Parent window
{
HRESULT hr = NOERROR;

ASSERT(m_cRef > 0);
ASSERT(m_pMessageSite);
ASSERT(m_pSession);
ASSERT(m_pMessage);

// ----- Give our user access to our form interface
if ((NULL != m_pMessageSite) && (NULL != m_pSession) && (NULL != m_pMessage))
{
g_pForm = this;

g_pForm->AddRef();
}

return hr;
}