/////////////////////////////////////////////////////////////////////
//
//	StdUtils.cpp
//
//	Utilities routines for any snapin.
//
//	HISTORY
//	t-danmo		96.10.10	Creation.
//
/////////////////////////////////////////////////////////////////////


#include "stdafx.h"
#include "stdutils.h"


/////////////////////////////////////////////////////////////////////
//	CompareMachineNames()
//
//	Compare if the strings refer to the same machine (computer).
//
//	Return 0 if both strings map to the same machine, otherwise
//	return -1 or +1 if machine name differs.
//
//	INTERFACE NOTES:
//	An empty string means the local machine.
//
//	HISTORY
//	02-Jun-97	t-danm		Creation.
//	14-Jul-97	t-danm		Comment update.
//	29-Jul-97	t-danm		Renamed from FCompareMachineNames().
//
int
CompareMachineNames(
	LPCTSTR pszMachineName1,
	LPCTSTR pszMachineName2)
	{
	TCHAR szThisMachineName[MAX_COMPUTERNAME_LENGTH + 4];

	BOOL fMachine1IsLocal = (pszMachineName1 == NULL || *pszMachineName1 == '\0');
	BOOL fMachine2IsLocal = (pszMachineName2 == NULL || *pszMachineName2 == '\0');
	if (fMachine1IsLocal)
		pszMachineName1 = szThisMachineName;
	if (fMachine2IsLocal)
		pszMachineName2 = szThisMachineName;
	if (pszMachineName1 == pszMachineName2)
		return 0;
	if (fMachine1IsLocal || fMachine2IsLocal)
		{
		// Get the computer name
		szThisMachineName[0] = _T('\\');
		szThisMachineName[1] = _T('\\');
		DWORD cchBuffer = MAX_COMPUTERNAME_LENGTH + 1;
		VERIFY(::GetComputerName(OUT &szThisMachineName[2], &cchBuffer));
		ASSERT(szThisMachineName[2] != _T('\\') && "Machine name has too many backslashes");
		}
	return lstrcmpi(pszMachineName1, pszMachineName2);
	} // CompareMachineNames()


/////////////////////////////////////////////////////////////////////
//	HrLoadOleString()
//
//	Load a string from the resource and return pointer to allocated
//	OLE string.
//
//	HISTORY
//	29-Jul-97	t-danm		Creation.
//
HRESULT
HrLoadOleString(
	UINT uStringId,					// IN: String Id to load from the resource
	OUT LPOLESTR * ppaszOleString)	// OUT: Pointer to pointer to allocated OLE string
	{
	if (ppaszOleString == NULL)
		{
		TRACE0("HrLoadOleString() - ppaszOleString is NULL.\n");
		return E_POINTER;
		}
	CString strT;		// Temporary string
	AFX_MANAGE_STATE(AfxGetStaticModuleState());	// Needed for LoadString()
	VERIFY( strT.LoadString(uStringId) );
    *ppaszOleString = reinterpret_cast<LPOLESTR>
            (CoTaskMemAlloc((strT.GetLength() + 1)* sizeof(wchar_t)));
	if (*ppaszOleString == NULL)
		return E_OUTOFMEMORY;
	USES_CONVERSION;
    wcscpy(OUT *ppaszOleString, T2OLE((LPTSTR)(LPCTSTR)strT));
	return S_OK;
	} // HrLoadOleString()

//
// Nodetype utility routines
// aNodetypeGuids must be defined by the subclass
//

int CheckObjectTypeGUID( const BSTR lpszObjectTypeGUID )
{
	ASSERT(NULL != lpszObjectTypeGUID);
	for (	int objecttype = 0;
			objecttype < g_cNumNodetypeGuids;
			objecttype += 1 )
	{
		if ( !::lstrcmpiW(lpszObjectTypeGUID,g_aNodetypeGuids[objecttype].bstr) )
			return objecttype;
	}
	ASSERT( FALSE );
	return 0;
}

int CheckObjectTypeGUID( const GUID* pguid )
{
	ASSERT(NULL != pguid);
	for (	int objecttype = 0;
			objecttype < g_cNumNodetypeGuids;
			objecttype += 1 )
	{
		if ( g_aNodetypeGuids[objecttype].guid == *pguid )
			return objecttype;
	}
	ASSERT( FALSE );
	return 0;
}

/////////////////////////////////////////////////////////////////////
//	FilemgmtCheckObjectTypeGUID()
//
//	Compare the GUID and return the objecttype associated with
//	the guid.
//	If no match found, return -1.
//
//	HISTORY
//	14-Jul-97	t-danm		Creation.  Inspired from CheckObjectTypeGUID()
//							but does not assert if the GUID is not found.
//
int FilemgmtCheckObjectTypeGUID(const GUID* pguid )
{
	ASSERT(NULL != pguid);
	for (	int objecttype = 0;
			objecttype < g_cNumNodetypeGuids;
			objecttype += 1 )
	{
		if ( g_aNodetypeGuids[objecttype].guid == *pguid )
			return objecttype;
	}
	return -1;
} // FilemgmtCheckObjectTypeGUID()


const BSTR GetObjectTypeString( int objecttype )
{
	if (objecttype < 0 || objecttype >= g_cNumNodetypeGuids)
	{
		ASSERT( FALSE );
		objecttype = 0;
	}
	return g_aNodetypeGuids[objecttype].bstr;
}

const GUID* GetObjectTypeGUID( int objecttype )
{
	if (objecttype < 0 || objecttype >= g_cNumNodetypeGuids)
	{
		ASSERT( FALSE );
		objecttype = 0;
	}
	return &(g_aNodetypeGuids[objecttype].guid);
}

//+--------------------------------------------------------------------------- 
//                                                                             
//  Function:   SynchronousCreateProcess                             
//                                                                             
//  Synopsis:   Invoke a separate UI process as a modal window.                                                    
//                                                                             
//---------------------------------------------------------------------------- 
HRESULT SynchronousCreateProcess(
    HWND    hWnd,
    LPCTSTR pszAppName,
    LPCTSTR pszCommandLine,
    LPDWORD lpdwExitCode
)
{
  HRESULT hr = S_OK;
  BOOL bReturn = FALSE;
  STARTUPINFO si;
  PROCESS_INFORMATION pi;

  //
  // disable the MMC main frame window to prevent it from
  // being shut down. The process we're going to create must
  // display a UI, such that, it behaves like a modal window.
  //
  ::EnableWindow(hWnd, FALSE);

  *lpdwExitCode = 0;

  ZeroMemory(&si, sizeof(STARTUPINFO));
  si.cb = sizeof(STARTUPINFO);
  
  bReturn = CreateProcess(
                pszAppName, //LPCTSTR lpApplicationName
                const_cast<LPTSTR>(pszCommandLine), //LPTSTR lpCommandLine
                NULL, //LPSECURITY_ATTRIBUTES lpProcessAttributes
                NULL, //LPSECURITY_ATTRIBUTES lpThreadAttributes
                FALSE, //BOOL bInheritHandles
                NORMAL_PRIORITY_CLASS, //DWORD dwCreationFlags
                NULL, //LPVOID lpEnvironment
                NULL, //lpCurrentDirectory
                &si, //LPSTARTUPINFO lpStartupInfo
                &pi //LPPROCESS_INFORMATION lpProcessInformation 
                );

  if (!bReturn)
  {
    hr = HRESULT_FROM_WIN32(GetLastError());
  } else
  {
    //
    // while process is still running, pump message to MMC main window,
    // such that it will repaint itself
    //
    while (TRUE)
    {
      MSG tempMSG;
      DWORD dwWait;

      while(::PeekMessage(&tempMSG,NULL, 0, 0, PM_REMOVE))
        DispatchMessage(&tempMSG);

      dwWait = MsgWaitForMultipleObjects(1, &(pi.hProcess), FALSE, INFINITE, QS_ALLINPUT);
      if ( 0 == (dwWait - WAIT_OBJECT_0))
        break;  // process is done
    };

    bReturn = GetExitCodeProcess(pi.hProcess, lpdwExitCode);
    if (!bReturn)
      hr = HRESULT_FROM_WIN32(GetLastError());

    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
  }

  //
  // enable MMC main frame window before return
  //
  ::EnableWindow(hWnd, TRUE);

  return hr;
}

/*

This code is not working yet.  The problem is that it hangs the
message loop, preventing redraw.  One possible approach is to disable the
top-level window and spin off a thread which waits for the process to stop,
then the thread reenables the top-level window and calls UpdateAllViews.

DWORD WINAPI ProcessMonitor(LPVOID pv)
{
}

class CSyncThread : public CThread
{
};

HRESULT SynchronousCreateProcess(LPCTSTR cpszCommandLine,
								 SynchronousProcessCompletionRoutine pfunc,
								 PVOID pvFuncParams)
// does not handle completion routine
{
	PROCESS_INFORMATION piProcInfo;
	(void) ::memset(&piProcInfo,0,sizeof(piProcInfo));
	STARTUPINFO si;
	(void) ::memset(&si,0,sizeof(si));
	::GetStartupInfo( &si );

	//
	// MarkL 1/30/97: Is pszCommandLine a static string?
	// It can not be read only. It is modified temporarily by the call
	// if you do not specify lpszImageName. There is no query to see
	// if a process is running. You can test to see if it has exited
	// using waitforsingleobject to see if the process object is signaled.
	//
	// MarkL also confirms that the handle should absolutely always
	// be signalled when the process dies.
	//
	LPTSTR pszCommandLine = (LPTSTR)
		::alloca(sizeof(TCHAR)*(::_tcslen(cpszCommandLine)+1));
	::_tcscpy(pszCommandLine,cpszCommandLine);
	if ( !::CreateProcess(
		NULL,			// LPCTSTR lpszImageName
		pszCommandLine,	// LPTSTR lpszCommandLine
		NULL,			// LPSECURITY_ATTRIBUTES lpsaProcess
		NULL,			// LPSECURITY_ATTRIBUTES lpsaThread
		FALSE,			// BOOL fInheritHandles
		0L,				// DWORD fdwCreate
		NULL,			// LPVOID lpvEnvironment
		NULL,			// LPTSTR lpszCurDir
		&si,			// LPSTARTUPINFO lpsiStartInfo
		&piProcInfo		// LPPROCESS_INFORMATION lppiProcInfo
		) )
	{
		DWORD dwErr = ::GetLastError();
		ASSERT( ERROR_SUCCESS != dwErr );
		return HRESULT_FROM_WIN32(dwErr);
	}
	ASSERT( NULL != piProcInfo.hProcess );

	VERIFY( WAIT_OBJECT_0 ==
		::WaitForSingleObject( piProcInfo.hProcess, INFINITE ) );

	VERIFY( ::CloseHandle( piProcInfo.hProcess ) );
	VERIFY( ::CloseHandle( piProcInfo.hThread  ) );
	return S_OK;
}
*/

LPOLESTR CoTaskAllocString( LPCOLESTR psz )
{
	if (NULL == psz)
		return NULL;
	LPOLESTR pszReturn = (LPOLESTR)CoTaskMemAlloc( (lstrlen(psz)+1)*sizeof(OLECHAR) );
	if (NULL != pszReturn)
		lstrcpy( pszReturn, psz );
	ASSERT( NULL != pszReturn );
	return pszReturn;
}

LPOLESTR CoTaskLoadString( UINT nResourceID )
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	// load the resource
	CString strText;
	strText.LoadString( nResourceID );
	ASSERT( !strText.IsEmpty() );
	return CoTaskAllocString( const_cast<BSTR>((LPCTSTR)strText) );
}