// ServicesPage.cpp : implementation file
//

#include "stdafx.h"
#include "wmsoapsvccp.h"
#include "ServicesPage.h"
#include "AddServiceDlg.h"
#include "EditServiceDlg.h"
#include "..\soap_source\SOAPAutomationProxy.h"
#include "..\soap_source\bytearrayconv.h"
#include "..\soap_source\WMSOAPWSDLClient.h"
#include "..\wmsoapstruct\wmsoapstruct.h"
#include "..\wmsoapstruct\wmsoapstruct_i.c"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CServicesPage property page

IMPLEMENT_DYNCREATE(CServicesPage, CPropertyPage)

CServicesPage::CServicesPage() : CPropertyPage(CServicesPage::IDD)
{
	//{{AFX_DATA_INIT(CServicesPage)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	m_bDirty = FALSE;
}

CServicesPage::~CServicesPage()
{
}

void CServicesPage::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CServicesPage)
	DDX_Control(pDX, IDC_BUTTON_EDIT, m_buttonEdit);
	DDX_Control(pDX, IDC_BUTTON_DELETE, m_buttonDelete);
	DDX_Control(pDX, IDC_BUTTON_ADD, m_buttonAdd);
	DDX_Control(pDX, IDC_LIST_SERVICES, m_listServices);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CServicesPage, CPropertyPage)
	//{{AFX_MSG_MAP(CServicesPage)
	ON_BN_CLICKED(IDC_BUTTON_ADD, OnButtonAdd)
	ON_BN_CLICKED(IDC_BUTTON_EDIT, OnButtonEdit)
	ON_BN_CLICKED(IDC_BUTTON_DELETE, OnButtonDelete)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CServicesPage message handlers

void CServicesPage::OnButtonAdd() 
{
	CAddServiceDlg dlg;

	if (dlg.DoModal() == IDOK)
	{
		char szBuffer[LIST_ITEM_BUFFER_SIZE];
		// check for duplication
		int nServices = m_listServices.GetItemCount();
		for (int i = 0; i < nServices; i++)
		{
			LV_ITEM item;
			item.mask = LVIF_TEXT;
			item.iItem = i;
			item.iSubItem = 0;
			item.pszText = szBuffer;
			item.cchTextMax = LIST_ITEM_BUFFER_SIZE;
			// get subitem0 (name) in 1st column
			if (m_listServices.GetItem(&item) != 0)
			{
				CString strData = item.pszText;
				if (dlg.m_strServiceName == strData)
				{
					strData.Format(_T("Error: Service <%s> already exists!\nNew Service not created."),
										dlg.m_strServiceName);
					AfxMessageBox(strData);
					return;
				}
			}
		}
		// place subitem0 (Service URL) in 1st column
		LV_ITEM item;
		item.mask = LVIF_TEXT;
		item.iItem = m_listServices.GetItemCount();
		item.iSubItem = 0;
		item.pszText = dlg.m_strServiceURI.GetBuffer(1);
		m_listServices.InsertItem(&item);
		dlg.m_strServiceURI.ReleaseBuffer(-1);
		// place subitem1 (Service Name) in 2nd column
		item.iSubItem = 1;
		item.pszText = dlg.m_strServiceName.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strServiceName.ReleaseBuffer(-1);
		// place subitem2 (Port Name) in 3rd column
		item.iSubItem = 2;
		item.pszText = dlg.m_strPortName.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strPortName.ReleaseBuffer(-1);
		// place subitem3 (WSDL file URL) in 4th column
		item.iSubItem = 3;
		item.pszText = dlg.m_strWSDLFileURL.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strWSDLFileURL.ReleaseBuffer(-1);
		// place subitem4 (Service ProgID) in 5th column
		item.iSubItem = 4;
		item.pszText = dlg.m_strServiceProgID.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strServiceProgID.ReleaseBuffer(-1);
		// place subitem5 (Header processor ProgID) in 6th column
		item.iSubItem = 5;
		item.pszText = dlg.m_strHeaderProcProgID.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strHeaderProcProgID.ReleaseBuffer(-1);
		// place subitem6 (Roles) in 7th column
		item.iSubItem = 6;
		item.pszText = dlg.m_strRoles.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strRoles.ReleaseBuffer(-1);
		// place subitem7 (Next Hop URL) in 8th column
		item.iSubItem = 7;
		item.pszText = dlg.m_strNextHopURL.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strNextHopURL.ReleaseBuffer(-1);
		// place subitem8 (Node URI) in 9th column
		item.iSubItem = 8;
		item.pszText = dlg.m_strNodeURI.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strNodeURI.ReleaseBuffer(-1);
		// place subitem9 (Enabled flag) in 10th column
		item.iSubItem = 9;
        if (dlg.m_bSvcEnabled == TRUE)
        {
            strcpy(item.pszText, "Yes");
        }
        else
        {
            strcpy(item.pszText, "No");
        }
		m_listServices.SetItem(&item);
		// done
		SetModified();
		m_bDirty = TRUE;
	}
}

void CServicesPage::OnButtonEdit() 
{
	int nItem = m_listServices.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);

	if (nItem == -1)
	{
		return;
	}
	char szBuffer[LIST_ITEM_BUFFER_SIZE];
	CEditServiceDlg dlg;

	LV_ITEM item;
	item.mask = LVIF_TEXT;
	item.iItem = nItem;
	item.iSubItem = 0;
	item.pszText = szBuffer;
	item.cchTextMax = LIST_ITEM_BUFFER_SIZE;
	// get subitem0 (Service URI) in 1st column
	if (m_listServices.GetItem(&item) == 0)
	{
		return;
	}
	dlg.m_strServiceURI = szBuffer;
	// get subitem1 (Service Name)
	item.iSubItem = 1;
	if (m_listServices.GetItem(&item) == 0)
	{
		return;
	}
	dlg.m_strServiceName = szBuffer;
	// get subitem2 (Port Name)
	item.iSubItem = 2;
	if (m_listServices.GetItem(&item) == 0)
	{
		return;
	}
	dlg.m_strPortName = szBuffer;
	// get subitem3 (WSDL file URL)
	item.iSubItem = 3;
	if (m_listServices.GetItem(&item) == 0)
	{
		return;
	}
	dlg.m_strWSDLFileURL = szBuffer;
	// get subitem4 (Service ProgID)
	item.iSubItem = 4;
	if (m_listServices.GetItem(&item) == 0)
	{
		return;
	}
	dlg.m_strServiceProgID = szBuffer;
	// get subitem5 (Header Proc ProgID)
	item.iSubItem = 5;
	if (m_listServices.GetItem(&item) == 0)
	{
		return;
	}
	dlg.m_strHeaderProcProgID = szBuffer;
	// get subitem6 (Roles)
	item.iSubItem = 6;
	if (m_listServices.GetItem(&item) == 0)
	{
		return;
	}
	dlg.m_strRoles = szBuffer;
	// get subitem7 (Next Hop URL)
	item.iSubItem = 7;
	if (m_listServices.GetItem(&item) == 0)
	{
		return;
	}
	dlg.m_strNextHopURL = szBuffer;
	// get subitem8 (Node URI)
	item.iSubItem = 8;
	if (m_listServices.GetItem(&item) == 0)
	{
		return;
	}
	dlg.m_strNodeURI = szBuffer;
	// get subitem9 (Enabled flag)
	item.iSubItem = 9;
	if (m_listServices.GetItem(&item) == 0)
	{
		return;
	}
    if (!strcmp(szBuffer, "Yes"))
    {
        dlg.m_bSvcEnabled = TRUE;
    }
    else
    {
        dlg.m_bSvcEnabled = FALSE;
    }
	if (dlg.DoModal() == IDOK)
	{
		// place subitem1 (Service Name) in 2nd column
		item.iSubItem = 1;
		item.pszText = dlg.m_strServiceName.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strServiceName.ReleaseBuffer(-1);
		// place subitem2 (Port Name) in 3rd column
		item.iSubItem = 2;
		item.pszText = dlg.m_strPortName.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strPortName.ReleaseBuffer(-1);
		// place subitem3 (WSDL file URL) in 4th column
		item.iSubItem = 3;
		item.pszText = dlg.m_strWSDLFileURL.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strWSDLFileURL.ReleaseBuffer(-1);
		// place subitem4 (Service ProgID) in 5th column
		item.iSubItem = 4;
		item.pszText = dlg.m_strServiceProgID.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strServiceProgID.ReleaseBuffer(-1);
		// place subitem5 (Header processor ProgID) in 6th column
		item.iSubItem = 5;
		item.pszText = dlg.m_strHeaderProcProgID.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strHeaderProcProgID.ReleaseBuffer(-1);
		// place subitem6 (Header processor Actor URL) in 7th column
		item.iSubItem = 6;
		item.pszText = dlg.m_strRoles.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strRoles.ReleaseBuffer(-1);
		// place subitem7 (Next Hop URL) in 8th column
		item.iSubItem = 7;
		item.pszText = dlg.m_strNextHopURL.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strNextHopURL.ReleaseBuffer(-1);
		// place subitem8 (Node URI) in 9th column
		item.iSubItem = 8;
		item.pszText = dlg.m_strNodeURI.GetBuffer(1);
		m_listServices.SetItem(&item);
		dlg.m_strNodeURI.ReleaseBuffer(-1);
		// place subitem9 (Enabled flag) in 10th column
		item.iSubItem = 9;
        if (dlg.m_bSvcEnabled == TRUE)
        {
            strcpy(item.pszText, "Yes");
        }
        else
        {
            strcpy(item.pszText, "No");
        }
		m_listServices.SetItem(&item);
		// done
		SetModified();
		m_bDirty = TRUE;
	}
}

void CServicesPage::OnButtonDelete() 
{
	int nItem = m_listServices.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);

	if (nItem != -1)
	{
		char szBuffer[LIST_ITEM_BUFFER_SIZE];

		LV_ITEM item;
		item.mask = LVIF_TEXT;
		item.iItem = nItem;
		item.iSubItem = 0;
		item.pszText = szBuffer;
		item.cchTextMax = LIST_ITEM_BUFFER_SIZE;
		if (m_listServices.GetItem(&item) == 0)
		{
			return;
		}

		CString strMsg = _T("Are you sure you want to\ndelete the SOAP Service URI: ");
		strMsg += szBuffer;
		strMsg += _T(" ?");
	
		if (AfxMessageBox(strMsg, MB_YESNO) == IDYES)
		{
			// delete Service from list ctrl
			m_listServices.DeleteItem(nItem);
			// the deed is done
			SetModified();
			m_bDirty = TRUE;
		}
	}
}

void CServicesPage::OnOK() 
{
	CWSSCPApp *pApp = (CWSSCPApp *)AfxGetApp();
	if (m_bDirty == TRUE && UpdateServices() == FALSE && pApp->m_bStaleNonce == true)
	{
		// server nonce stale, reauthenticate
		if (UpdateServices() == FALSE)
		{
			AfxMessageBox(_T("Failed to update settings on Server!"));
		}
	}
	CPropertyPage::OnOK();
}

BOOL CServicesPage::OnInitDialog() 
{
	CWSSCPApp *pApp = (CWSSCPApp *)AfxGetApp();
	CPropertyPage::OnInitDialog();
	
	if (SetupServicesList() == FALSE)
	{
		AfxMessageBox(_T("Failed to intialize Services list!"));
	}
	if (QueryServices() == FALSE && pApp->m_bStaleNonce == true)
	{
		// server nonce stale, reauthenticate
		if (QueryServices() == FALSE)
		{
			AfxMessageBox(_T("Failed to obtain Services Info from Server!"));
		}
	}	
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

BOOL CServicesPage::SetupServicesList()
{
	char szBuffer[LIST_ITEM_BUFFER_SIZE];
	char *ppszTitles[] = {
		_T("URI"), _T("Service"), _T("Port"), _T("WSDL file URL"), _T("Body Handler"), _T("Header Handlers"), _T("Roles"), _T("Next Hop"), _T("Node URI"), _T("Enabled")};
	const int nNumCols = 10;

	// calculate and set column width
	RECT r;
	m_listServices.GetClientRect(&r);
	LV_COLUMN lvc;
	float f = (float)r.right / (float)(nNumCols);

	for (int i = 0; i < nNumCols; i++)
	{
		lstrcpy(szBuffer, ppszTitles[i]);
	
		lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
		lvc.fmt = LVCFMT_LEFT;
		lvc.pszText = szBuffer;
		lvc.iSubItem = i;
        switch (i)
        {
        case 0:
            lvc.cx = (int)(4.0 * f);
            break;
        case 3:
            lvc.cx = (int)(5.0 * f);
            break;
        case 9:
            lvc.cx = (int)(1.5 * f);
            break;
        default:
		    lvc.cx = (int)(3.0 * f);
        }
		if (m_listServices.InsertColumn(i,&lvc) == -1)
		{
			return FALSE;
		}
	}
	return TRUE;
}

BOOL CServicesPage::QueryServices()
{
	CWaitCursor wait;
	CWSSCPApp *pApp = (CWSSCPApp *)AfxGetApp();
	// renew the message object
	if (pApp->m_SOAPClient.NewMessage() == false)
	{
		return FALSE;
	}
	// method
	wstring wstrMethodName = L"GetServiceInfo";
	// set up call
	_variant_t Args[1];
	wstring Names[1];
	_variant_t varReturn;
	// set up param
	Args[0].vt = VT_VARIANT | VT_ARRAY;
	Args[0].parray = NULL;
	Names[0] = L"SvcInfo";

	int nNumArgs = 1;

	// generate SOAP request message headers
	pApp->BuildRequestHeaders();

	// message buffer strings
	string strRequestXML;
	string strResponseXML;

	// attempt method invocation
	bool bFault = false;
	if (pApp->m_SOAPClient.InvokeSOAPMethod(wstrMethodName,
											Names,
											Args,
											nNumArgs,
											varReturn) == false)
	{
		bFault = true;
	}
	if (pApp->m_bViewBuffers == true)
	{
		MessageBox(pApp->m_SOAPClient.GetXMLOut(), "Request Message", MB_OK);
		MessageBox(pApp->m_SOAPClient.GetXMLIn(), "Response Message", MB_OK);
	}
	// load response message headers
	pApp->GetResponseHeaders();

	if (bFault == true ||
		varReturn.boolVal == VARIANT_FALSE ||
		pApp->m_SOAPClient.IsSOAPFault() == true ||
		pApp->AuthServer() == false)
	{
		return FALSE;
	}
	// fill up name array
    const int nNumMembers = 10;
	BSTR bstrNames[nNumMembers];
	bstrNames[0] = SysAllocString(L"SvcURI");
	bstrNames[1] = SysAllocString(L"SvcName");
	bstrNames[2] = SysAllocString(L"Port");
	bstrNames[3] = SysAllocString(L"WSDL_URL");
	bstrNames[4] = SysAllocString(L"SvcProgID");
	bstrNames[5] = SysAllocString(L"HdrProgIDs");
	bstrNames[6] = SysAllocString(L"Roles");
	bstrNames[7] = SysAllocString(L"NextHopURL");
	bstrNames[8] = SysAllocString(L"NodeURI");
	bstrNames[9] = SysAllocString(L"Enabled");
	// extract info from SAFEARRAY
	VARIANT *pVar = NULL;
	SAFEARRAY *pArray = Args[0].parray;
	long arrIndex[1];
	char szBuffer[LIST_ITEM_BUFFER_SIZE];
	LV_ITEM item;
	item.mask = LVIF_TEXT;
	item.pszText = szBuffer;
	// lock array
	SafeArrayLock(pArray);
	for (unsigned int i = pArray->rgsabound[0].lLbound;
			i < (pArray->rgsabound[0].lLbound + pArray->rgsabound[0].cElements);
			i++)
	{
		// the SAFEARRAY contains as elements VARIANTS whose pdispVal value
		// contains an IDispatch pointer which is used to access the structure object.
		arrIndex[0] = i;
		SafeArrayPtrOfIndex(pArray, arrIndex, (void **)&pVar);
		IDispatch *pIDispatch = pVar->pdispVal;
		Iwmsoapstruct *pIwmsoapstruct;
		HRESULT res = pIDispatch->QueryInterface(IID_Iwmsoapstruct, (void **)&pIwmsoapstruct);
		if (FAILED(res))
		{
			return FALSE;
		}
		CString strTemp;
		_variant_t varTemp;
		VARIANT_BOOL bResult;
		// place items in columns
		item.iItem = i - pArray->rgsabound[0].lLbound;
		// Service URI
		pIwmsoapstruct->GetMember(bstrNames[0], &varTemp, &bResult);
		strTemp = varTemp.bstrVal;
		lstrcpy(szBuffer, (LPCTSTR)strTemp);
		item.iSubItem = 0;
		{
			m_listServices.InsertItem(&item);
		}
		for (int j = 1; j < nNumMembers; j++)
		{
			// all others
			item.iSubItem = j;
			pIwmsoapstruct->GetMember(bstrNames[j], &varTemp, &bResult);
            if (j == 5 || j == 6)
            {
                // header proc ids or roles
	            SAFEARRAY *pArray = varTemp.parray;
	            long arrIndex[1];
                wstring wstrTemp;
                int counter = 0;
	            for (unsigned int i = pArray->rgsabound[0].lLbound;
			            i < (pArray->rgsabound[0].lLbound + pArray->rgsabound[0].cElements);
			            i++)
	            {
		            arrIndex[0] = i;
		            // get pointer to struct object
		            VARIANT *pVar = NULL;
		            SafeArrayPtrOfIndex(pArray, arrIndex, (void **)&pVar);
                    if (counter++ > 0)
                    {
                        wstrTemp += ' ';
                    }
                    wstrTemp += pVar->bstrVal;
                }
                strTemp = wstrTemp.c_str();
            }
            else if (j == 9)
            {
                // boolean value enabled is "true"
                strTemp = (varTemp.boolVal == VARIANT_TRUE ? "Yes" : "No");
            }
            else
            {
			    strTemp = varTemp.bstrVal;
            }
			lstrcpy(szBuffer, (LPCTSTR)strTemp);
			m_listServices.SetItem(&item);
		}
		// release interface ptr
		pIwmsoapstruct->Release();
	}
	// done with names
	for (int j = 0; j < nNumMembers; j++)
	{
		SysFreeString(bstrNames[j]);
	}
	SafeArrayUnlock(pArray);
	m_listServices.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
	m_listServices.SetFocus();
	return TRUE;
}

BOOL CServicesPage::UpdateServices()
{
	CWaitCursor wait;
	CWSSCPApp *pApp = (CWSSCPApp *)AfxGetApp();
	// renew the message object
	if (pApp->m_SOAPClient.NewMessage() == false)
	{
		return FALSE;
	}
	// method
	wstring wstrMethodName = L"SetServiceInfo";
	// set up call
	_variant_t Args[1];
	wstring Names[1];
	_variant_t varReturn;
	// set up param
	SAFEARRAYBOUND Bounds[1];
	int nNumServices = m_listServices.GetItemCount();
	Bounds[0].lLbound = 0;
	Bounds[0].cElements = nNumServices;
	SAFEARRAY *pArray = SafeArrayCreate(VT_VARIANT, 1, Bounds);
	if (pArray == NULL)
	{
		return FALSE;
	}
	// fill up name array
    const int nNumMembers = 10;
	BSTR bstrNames[nNumMembers];
	bstrNames[0] = SysAllocString(L"SvcURI");
	bstrNames[1] = SysAllocString(L"SvcName");
	bstrNames[2] = SysAllocString(L"Port");
	bstrNames[3] = SysAllocString(L"WSDL_URL");
	bstrNames[4] = SysAllocString(L"SvcProgID");
	bstrNames[5] = SysAllocString(L"HdrProgIDs");
	bstrNames[6] = SysAllocString(L"Roles");
	bstrNames[7] = SysAllocString(L"NextHopURL");
	bstrNames[8] = SysAllocString(L"NodeURI");
	bstrNames[9] = SysAllocString(L"Enabled");
	// fill array
	char szBuffer[LIST_ITEM_BUFFER_SIZE];
	LV_ITEM item;
	item.mask = LVIF_TEXT;
	item.pszText = szBuffer;
	item.cchTextMax = LIST_ITEM_BUFFER_SIZE;
	long arrIndex[1];
	// iterate over service list
	for (int i = 0; i < nNumServices; i++)
	{
		// instantiate struct object
		Iwmsoapstruct *pIwmsoapstructOut;
		HRESULT res = CoCreateInstance( CLSID_wmsoapstruct,
										NULL, CLSCTX_SERVER,
										IID_Iwmsoapstruct,
										(void **) &pIwmsoapstructOut);
		if (FAILED(res))
		{
			SafeArrayDestroy(pArray);
			return FALSE;
		}
		item.iItem = i;
		_variant_t varTemp;
		for (int j = 0; j < nNumMembers; j++)
		{
			item.iSubItem = j;
			// get subitem
			if (m_listServices.GetItem(&item) != 0)
			{
                if (j == 5 || j == 6)
                {
					// Header processor ProgIds or Roles
                    vector<string> arrValues;
                    char *pszDelimiters = " ";
                    char *p = strtok(item.pszText, pszDelimiters);
                    while (p != NULL)
                    {
                        arrValues.push_back(string(p));
                        p = strtok(NULL, pszDelimiters);
                    }
	                // set up param
	                SAFEARRAYBOUND Bounds[1];
	                Bounds[0].lLbound = 0;
	                Bounds[0].cElements = arrValues.size();
	                SAFEARRAY *pArray = SafeArrayCreate(VT_VARIANT, 1, Bounds);
	                if (pArray == NULL)
	                {
		                return FALSE;
	                }
                    varTemp.parray = pArray;
                    varTemp.vt = (VT_ARRAY | VT_VARIANT);
                    _variant_t varItem;
                	long arrIndex[1];
                    for (unsigned int i = 0; i < arrValues.size(); i++)
                    {
                        varItem = arrValues[i].c_str();
		                arrIndex[0] = i;
		                // put it away
		                SafeArrayPutElement(pArray, arrIndex, &varItem);
                    }
                }
                else if (j == 9)
                {
                    // boolean value for "Enabled"
                    if (!strcmp(item.pszText, "Yes"))
                    {
                        varTemp = true;
                    }
                    else
                    {
                        varTemp = false;
                    }
                }
                else
                {
				    varTemp = item.pszText;
                }
				VARIANT_BOOL bResult;
				pIwmsoapstructOut->SetMember(bstrNames[j], varTemp, &bResult);
			    varTemp.Clear();
			}
		}
		// now get IDispatch pointer
		IDispatch *pIDispatchOut;
		res = pIwmsoapstructOut->QueryInterface(IID_IDispatch, (void **)&pIDispatchOut);
		if (FAILED(res))
		{
			SafeArrayDestroy(pArray);
			return FALSE;
		}
		// release
		pIwmsoapstructOut->Release();
		// set up variant with IDispatch ptr
		varTemp.vt = VT_DISPATCH;
		varTemp.pdispVal = pIDispatchOut;
		arrIndex[0] = i;
		// put it away
		SafeArrayPutElement(pArray, arrIndex, &varTemp);
		varTemp.Clear();
	}
	// done with names
	for (int j = 0; j < nNumMembers; j++)
	{
		SysFreeString(bstrNames[j]);
	}

	Args[0].vt = VT_VARIANT | VT_ARRAY;
	Args[0].parray = pArray;
	Names[0] = L"SvcInfo";

	int nNumArgs = 1;

	// generate SOAP request message headers
	pApp->BuildRequestHeaders();

	// message buffer strings
	string strRequestXML;
	string strResponseXML;

	// attempt method invocation
	bool bFault = false;
	if (pApp->m_SOAPClient.InvokeSOAPMethod(wstrMethodName,
											Names,
											Args,
											nNumArgs,
											varReturn) == false)
	{
		bFault = true;
	}
	if (pApp->m_bViewBuffers == true)
	{
		MessageBox(pApp->m_SOAPClient.GetXMLOut(), "Request Message", MB_OK);
		MessageBox(pApp->m_SOAPClient.GetXMLIn(), "Response Message", MB_OK);
	}
	// load response message headers
	pApp->GetResponseHeaders();

	if (bFault == true ||
		varReturn.boolVal == VARIANT_FALSE ||
		pApp->m_SOAPClient.IsSOAPFault() == true ||
		pApp->AuthServer() == false)
	{
		return FALSE;
	}
	m_bDirty = FALSE;
	return TRUE;
}