
//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1993.
//
//  File:	olereg.cpp
//
//  Contents:	Helper routines to interrogate the reg database
//
//  Classes:
//
//  Functions:	OleRegGetUserType
//		OleRegGetMiscStatus
//		OleGetAutoConvert
//		OleSetAutoConvert	
//
//  History:    dd-mmm-yy Author    Comment
//		11-Jan-94 alexgo    added VDATEHEAP macros to every function
//		30-Nov-93 alexgo    32bit port
//		11-Nov-92 jasonful  author
//
//--------------------------------------------------------------------------

#include <le2int.h>
#pragma SEG(olereg)

#include <reterr.h>
#include "oleregpv.h"
#include <ctype.h>

ASSERTDATA
#define MAX_STR 512

// Reg Db Keys
static const OLECHAR szAuxUserTypeKey[] 	= OLESTR("AuxUserType");
static const OLECHAR szMiscStatusKey[]  	= OLESTR("MiscStatus") ;
static const OLECHAR szProgIDKey[]  		= OLESTR("ProgID");
static const OLECHAR szClsidKey[] 	  	= OLESTR("Clsid");
static const OLECHAR szAutoConverTo[]	 = OLESTR("AutoConvertTo");

// this is really a global variable
const OLECHAR szClsidRoot[] 	= OLESTR("CLSID\\");


static INTERNAL OleRegGetDword
	(HKEY 		hkey,
	LPCOLESTR	szKey,
	DWORD FAR*	pdw);

static INTERNAL OleRegGetDword
	(HKEY 		hkey,
	DWORD 	    	dwKey,
	DWORD FAR*	pdw);

static INTERNAL OleRegGetString
	(HKEY 		hkey,
	LPCOLESTR	szKey,
	LPOLESTR FAR*	pszValue);


static  INTERNAL OleRegGetString
	(HKEY 		hkey,
	DWORD 	    	dwKey,
	LPOLESTR FAR*	pszValue);

//+-------------------------------------------------------------------------
//
//  Function: 	Atol (static)
//
//  Synopsis:   Converts string to integer
//
//  Effects:
//
//  Arguments:  [sz]	-- the string
//
//  Requires:
//
//  Returns: 	LONG
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		30-Nov-93 alexgo    32bit port
//
//  Notes:  	32bit OLE just uses wcstol as a #define
//
//		original 16bit comment:
//
// 		Replacement for stdlib atol,
// 		which didn't work and doesn't take far pointers.
// 		Must be tolerant of leading spaces.
//
//--------------------------------------------------------------------------
#ifndef WIN32
#pragma SEG(Atol)
FARINTERNAL_(LONG) Atol
	(LPOLESTR sz)
{
	VDATEHEAP();

	signed int 	sign = +1;
	UINT 		base = 10;
	LONG 		l = 0;

	if (NULL==sz)
	{
		Assert (0);
		return 0;
	}
	while (isspace(*sz))
	{
		sz++;
	}
	
	if (*sz== OLESTR('-'))
	{
		sz++;
		sign = -1;
	}	
	if (sz[0]==OLESTR('0') && sz[1]==OLESTR('x'))
	{
		base = 16;	
		sz+=2;
	}

	if (base==10)
	{
		while (isdigit(*sz))
		{
			l = l * base + *sz - OLESTR('0');
			sz++;
		}
	}
	else
	{
		Assert (base==16);
		while (isxdigit(*sz))
		{
			l = l * base + isdigit(*sz) ? *sz - OLESTR('0') :
				toupper(*sz) - OLESTR('A') + 10;
		 	sz++;
		}
	}
	return l * sign;
}
#endif  //!WIN32



//+-------------------------------------------------------------------------
//
//  Function: 	OleRegGetDword
//
//  Synopsis:   returns the value of subkey "szKey" as a DWORD
//
//  Effects:
//
//  Arguments:  [hkey]	-- handle to a key in the regdb
//		[szKey]	-- the subkey to look for
//		[pdw]	-- where to put the dword
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		30-Nov-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(OleRegGetDword)
static INTERNAL OleRegGetDword
	(HKEY 		hkey,
	LPCOLESTR 	szKey,
	DWORD FAR*	pdw)
{
	VDATEHEAP();

	VDATEPTRIN (pdw, DWORD);
	
	LPOLESTR 	szLong = NULL;
	
	HRESULT hresult = OleRegGetString (hkey, szKey, &szLong);
	if (hresult != NOERROR)
	{
		return hresult;
	}
	*pdw = Atol (szLong);
	PubMemFree(szLong);
	return NOERROR;
}

//+-------------------------------------------------------------------------
//
//  Function:	OleRegGetDword (overloaded)
//
//  Synopsis:   Gets a dword from a sub-key given as a dword
//
//  Effects:
//
//  Arguments:  [hkey]	-- handle to a key in the regdb
//		[dwKey]	-- number to convert to a string key to lookup in
//			   the regdb
//		[pdw]	-- where to put the dword
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		30-Nov-93 alexgo    32bit port
//
//  Notes: 	REVIEW32:  This deep layering is kinda strange, as each
//		overloaded function is used exactly once.  It might be
//		better just to inline the stuff and be done with it.
//
//--------------------------------------------------------------------------

#pragma SEG(OleRegGetDword)
static  INTERNAL OleRegGetDword
	(HKEY 		hkey,
	DWORD 	    	dwKey,
	DWORD FAR*	pdw)
{
	VDATEHEAP();

	OLECHAR szBuf[MAX_STR];
	wsprintf(szBuf, OLESTR("%ld"), dwKey);
	
	return OleRegGetDword (hkey, szBuf, pdw);
}

//+-------------------------------------------------------------------------
//
//  Function: 	OleRegGetString
//
//  Synopsis:   Return the value of subkey [szKey] of key [hkey] as a string
//
//  Effects:
//
//  Arguments:  [hkey]		-- a handle to a key in the reg db
//		[szKey]		-- the subkey to get the value of
//		[ppszValue]	-- where to put the value string
//
//  Requires:
//
//  Returns:    HRESULT (NOERROR, E_OUTOFMEMORY, REGDB_E_KEYMISSING)
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//		15-Dec-93 ChrisWe   cb is supposed to be the size of the
//				    buffer in bytes; changed to use sizeof()
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(OleRegGetString)
static INTERNAL OleRegGetString
	(HKEY 		hkey,
	LPCOLESTR	szKey,
	LPOLESTR FAR*	ppszValue)
{
	VDATEHEAP();

	OLECHAR 	szBuf [MAX_STR];
    	LONG 		cb = sizeof(szBuf);

	*ppszValue = NULL;

    	if (ERROR_SUCCESS == RegQueryValue (hkey, (LPOLESTR) szKey,
    		szBuf, &cb))
	{
		*ppszValue = UtDupString (szBuf);	
		return *ppszValue ? NOERROR : ResultFromScode (E_OUTOFMEMORY);
	}
	return ReportResult(0, REGDB_E_KEYMISSING, 0, 0);
}

//+-------------------------------------------------------------------------
//
//  Function: 	OleRegGetString (overloaded)
//
//  Synopsis: 	Gets the string value of the DWORD subkey
//
//  Effects:
//
//  Arguments:  [hkey]		-- handle to a key in the regdb
//		[dwKey]		-- the subkey value
//		[ppszValue]	-- where to put the return value
//
//  Requires:
//
//  Returns:	HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

static INTERNAL OleRegGetString
	(HKEY 		hkey,
	DWORD 	    	dwKey,
	LPOLESTR FAR*	ppszValue)
{
	VDATEHEAP();

	OLECHAR szBuf[MAX_STR];
	wsprintf(szBuf, OLESTR("%ld"), dwKey);
	
	return OleRegGetString (hkey, szBuf, ppszValue);
}

//+-------------------------------------------------------------------------
//
//  Function: 	OleRegGetUserType
//
//  Synopsis:   Returns the user type name for the class id.
//
//  Effects:
//
//  Arguments: 	[clsid]		-- the class ID to look up
//		[dwFormOfType]	-- flag indicating whether the fullname,
//				   shortname, or app name is desired
//		[ppszUserType]	-- where to put the type string
//
//  Requires: 	returned string must be deleted
//
//  Returns:    HRESULT (NOERROR, OLE_E_CLSID)
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Nov-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(OleRegGetUserType)
STDAPI OleRegGetUserType
	(REFCLSID	clsid,
	DWORD		dwFormOfType,  // as in IOleObject::GetUserType
	LPOLESTR FAR*  	ppszUserType)   // out parm
{
	VDATEHEAP();

	HKEY 		hkeyClsid 	= NULL;
	HKEY 		hkeyAux		= NULL;
	HRESULT 	hresult 	= NOERROR;

	VDATEPTROUT (ppszUserType, LPOLESTR);
	*ppszUserType = NULL;
	ErrRtnH(CoOpenClassKey(clsid, &hkeyClsid));
	
	if (dwFormOfType == USERCLASSTYPE_FULL ||
		ERROR_SUCCESS != RegOpenKey (hkeyClsid, szAuxUserTypeKey,
		&hkeyAux))
	{
		// use Main User Type Name (value of key CLSID(...))
		ErrRtnH (OleRegGetString (hkeyClsid, (LPOLESTR)NULL,
			ppszUserType));
	}
	else
	{
		// look under key AuxUserType
		if (NOERROR !=
			OleRegGetString (hkeyAux, dwFormOfType, ppszUserType)
			|| NULL==*ppszUserType
			|| '\0'==(*ppszUserType)[0])
		{
			// Couldn't find the particular FormOfType requested,
			// so use Full User Type Name (value of main
			// CLSID key), as per spec
			ErrRtnH (OleRegGetString (hkeyClsid, (LPOLESTR)NULL,
				ppszUserType));
		}
	}

  errRtn:

	CLOSE (hkeyClsid);
	CLOSE (hkeyAux);

	return hresult;
}

//+-------------------------------------------------------------------------
//
//  Function: 	OleRegGetMiscStatus
//
//  Synopsis:   Retrieves misc status bits from the reg db
//
//  Effects:
//
//  Arguments:  [clsid]		-- the class ID
//		[dwAspect]	-- specify the aspect (used in querrying
//				   the reg db)
//		[pdwStatus]	-- return to return the status bits
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:  	Uses default (0) is the MiscStatus key is missing
//
//--------------------------------------------------------------------------

#pragma SEG(OleRegGetMiscStatus)
STDAPI OleRegGetMiscStatus
	(REFCLSID	clsid,
	DWORD		dwAspect,
	DWORD FAR*	pdwStatus)
{
	VDATEHEAP();

	HKEY 		hkeyClsid 	= NULL;
	HKEY 		hkeyMisc 	= NULL;
	HRESULT 	hresult		= NOERROR;

	VDATEPTROUT(pdwStatus, DWORD);
	*pdwStatus = 0;

	ErrRtnH(CoOpenClassKey(clsid, &hkeyClsid));
	
	// Open MiscStatus key
	if (ERROR_SUCCESS != RegOpenKey (hkeyClsid, szMiscStatusKey,
		&hkeyMisc))
	{
		// MiscStatus key not there, so use default.
		hresult = NOERROR;
		goto errRtn;
	}
	if (OleRegGetDword (hkeyMisc, dwAspect, pdwStatus) != NOERROR)
	{
		// Get default value from main Misc key
		ErrRtnH (OleRegGetDword (hkeyMisc,
			(LPOLESTR)NULL, pdwStatus));
		// Got default value
	}
	// Got value for dwAspect

  errRtn:
	CLOSE (hkeyMisc);
	CLOSE (hkeyClsid);

	return hresult;
}

//+-------------------------------------------------------------------------
//
//  Function:	OleGetAutoConvert
//
//  Synopsis:   Retrieves the class ID that [clsidOld] should be converted
//		to via auto convert
//
//  Effects:
//
//  Arguments:  [clsidOld]	-- the original class ID
//		[pClsidNew]	-- where to put the new convert-to class ID
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              05-Apr-94 kevinro   removed bogus assert, restructured
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(OleGetAutoConvert)
STDAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
{
	VDATEHEAP();

	HRESULT hresult;
	HKEY hkeyClsid = NULL;
	LPOLESTR lpszClsid = NULL;
	VDATEPTROUT (pClsidNew, CLSID);
	*pClsidNew = CLSID_NULL;

	hresult = CoOpenClassKey(clsidOld, &hkeyClsid);
	if (FAILED(hresult))
	{
	    return(hresult);
	}

	hresult = OleRegGetString(hkeyClsid, szAutoConverTo, &lpszClsid);

	if (SUCCEEDED(hresult))
	{
	    // convert string into CLSID
	    hresult = CLSIDFromString(lpszClsid, pClsidNew);
	}

	CLOSE(hkeyClsid);
	
	PubMemFree(lpszClsid);
	return hresult;
}

//+-------------------------------------------------------------------------
//
//  Function: 	OleSetAutoConvert
//
//  Synopsis:   Sets the autoconvert information in the regdb
//
//  Effects:
//
//  Arguments:  [clsidOld]	-- the original class id
//		[clsidNew]	-- that class id that [clsidOld] should be
//				   auto-converted to
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(OleSetAutoConvert)
STDAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
{
	VDATEHEAP();

	HRESULT 	hresult;
	HKEY 		hkeyClsid = NULL;

	ErrRtnH(CoOpenClassKey(clsidOld, &hkeyClsid));

	if (IsEqualCLSID(clsidNew, CLSID_NULL))
	{
		// ignore error since there may not be a value at present
		(void)RegDeleteKey(hkeyClsid, szAutoConverTo);
	}
	else
	{
		OLECHAR szClsid[MAX_STR];
		Verify(StringFromCLSID2(clsidNew, szClsid, sizeof(szClsid))
			!= 0);

		if (RegSetValue(hkeyClsid, szAutoConverTo, REG_SZ, szClsid,
			_xstrlen(szClsid)) != ERROR_SUCCESS)
		{
			hresult = ResultFromScode(REGDB_E_WRITEREGDB);
		}
	}

errRtn:
	CLOSE(hkeyClsid);
	
	return hresult;
}


