692 lines
18 KiB
C++
692 lines
18 KiB
C++
//+--------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1992.
|
|
//
|
|
// File: storage.cxx
|
|
//
|
|
// Contents: Contains generic storage APIs
|
|
//
|
|
// History: 05-Oct-92 DrewB Created
|
|
//
|
|
//---------------------------------------------------------------
|
|
|
|
#include <exphead.cxx>
|
|
#pragma hdrstop
|
|
|
|
#include <dfentry.hxx>
|
|
#include <storagep.h>
|
|
#include <logfile.hxx>
|
|
#include <df32.hxx>
|
|
#ifdef COORD
|
|
#include <oledb.h>
|
|
#endif //COORD
|
|
|
|
#include <trace.hxx>
|
|
|
|
#include <ole2sp.h>
|
|
#include <ole2com.h>
|
|
|
|
|
|
//+--------------------------------------------------------------
|
|
//
|
|
// Function: StgOpenStorage, public
|
|
//
|
|
// Synopsis: Instantiates a root storage from a file
|
|
// by binding to the appropriate implementation
|
|
// and starting things up
|
|
//
|
|
// Arguments: [pwcsName] - Name
|
|
// [pstgPriority] - Priority mode reopen IStorage
|
|
// [grfMode] - Permissions
|
|
// [snbExclude] - Exclusions for priority reopen
|
|
// [reserved]
|
|
// [ppstgOpen] - Docfile return
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: [ppstgOpen]
|
|
//
|
|
// History: 05-Oct-92 DrewB Created
|
|
//
|
|
//---------------------------------------------------------------
|
|
|
|
STDAPI StgOpenStorage(OLECHAR const *pwcsName,
|
|
IStorage *pstgPriority,
|
|
DWORD grfMode,
|
|
SNB snbExclude,
|
|
LPSTGSECURITY reserved,
|
|
IStorage **ppstgOpen)
|
|
{
|
|
return DfOpenDocfile(pwcsName, NULL, pstgPriority, grfMode,
|
|
snbExclude, reserved, NULL, 0, ppstgOpen);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CheckSignature, private
|
|
//
|
|
// Synopsis: Checks the given memory against known signatures
|
|
//
|
|
// Arguments: [pb] - Pointer to memory to check
|
|
//
|
|
// Returns: S_OK - Current signature
|
|
// S_FALSE - Beta 2 signature, but still successful
|
|
// Appropriate status code
|
|
//
|
|
// History: 23-Jul-93 DrewB Created from header.cxx code
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//Identifier for first bytes of Beta 1 Docfiles
|
|
const BYTE SIGSTG_B1[] = {0xd0, 0xcf, 0x11, 0xe0, 0x0e, 0x11, 0xfc, 0x0d};
|
|
const USHORT CBSIGSTG_B1 = sizeof(SIGSTG_B1);
|
|
|
|
//Identifier for first bytes of Beta 2 Docfiles
|
|
const BYTE SIGSTG_B2[] = {0x0e, 0x11, 0xfc, 0x0d, 0xd0, 0xcf, 0x11, 0xe0};
|
|
const BYTE CBSIGSTG_B2 = sizeof(SIGSTG_B2);
|
|
|
|
SCODE CheckSignature(BYTE *pb)
|
|
{
|
|
SCODE sc;
|
|
|
|
olDebugOut((DEB_ITRACE, "In CheckSignature(%p)\n", pb));
|
|
|
|
// Check for ship Docfile signature first
|
|
if (memcmp(pb, SIGSTG, CBSIGSTG) == 0)
|
|
sc = S_OK;
|
|
|
|
// Check for Beta 2 Docfile signature
|
|
else if (memcmp(pb, SIGSTG_B2, CBSIGSTG_B2) == 0)
|
|
sc = S_FALSE;
|
|
|
|
// Check for Beta 1 Docfile signature
|
|
else if (memcmp(pb, SIGSTG_B1, CBSIGSTG_B1) == 0)
|
|
sc = STG_E_OLDFORMAT;
|
|
else
|
|
sc = STG_E_INVALIDHEADER;
|
|
|
|
olDebugOut((DEB_ITRACE, "Out CheckSignature => %lX\n", sc));
|
|
return sc;
|
|
}
|
|
|
|
//+--------------------------------------------------------------
|
|
//
|
|
// Function: StgIsStorageFileHandle, private
|
|
//
|
|
// Synopsis: Determines whether a handle is open on a storage file.
|
|
// Spun off from StgIsStorageFile. Internaly we use this
|
|
//
|
|
// Arguments: [hf] - Open File Handle (caller must seek it to 0)
|
|
//
|
|
// Returns: S_OK, S_FALSE or error codes
|
|
//
|
|
// History: 07-May-98 MikeHill Created
|
|
// 05-June-98 BChapman Return Errors not just S_FALSE.
|
|
// Add optional Overlapped pointer.
|
|
//
|
|
//---------------------------------------------------------------
|
|
|
|
|
|
STDAPI StgIsStorageFileHandle( HANDLE hf, LPOVERLAPPED povlp )
|
|
{
|
|
DWORD cbRead;
|
|
BYTE stgHeader[sizeof(SStorageFile)];
|
|
SCODE sc;
|
|
LONG status;
|
|
OVERLAPPED ovlp;
|
|
|
|
FillMemory( stgHeader, sizeof(SStorageFile), 0xDE );
|
|
|
|
if (povlp == NULL)
|
|
{
|
|
ovlp.Offset = 0;
|
|
ovlp.OffsetHigh = 0;
|
|
ovlp.hEvent = NULL;
|
|
}
|
|
|
|
if( !ReadFile( hf,
|
|
&stgHeader,
|
|
sizeof( stgHeader ),
|
|
&cbRead,
|
|
(povlp == NULL) ? &ovlp : povlp ) )
|
|
{
|
|
if( NULL != povlp )
|
|
{
|
|
status = GetLastError();
|
|
if( ERROR_IO_PENDING == status)
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
if( !GetOverlappedResult( hf, povlp, &cbRead, TRUE ) )
|
|
status = GetLastError();
|
|
}
|
|
if(ERROR_SUCCESS != status && ERROR_HANDLE_EOF != status)
|
|
olChk( HRESULT_FROM_WIN32( status ) );
|
|
}
|
|
else
|
|
olErr( EH_Err, S_FALSE );
|
|
}
|
|
|
|
// Don't worry about short reads. If the read is short then
|
|
// the signature checks will fail.
|
|
|
|
sc = CheckSignature( ((SStorageFile*)stgHeader)->abSig );
|
|
if(S_OK == sc)
|
|
goto EH_Err; // Done, return "Yes"
|
|
|
|
olChk(sc);
|
|
|
|
// It didn't error. sc != S_OK then it
|
|
// Must be S_FALSE.
|
|
olAssert(S_FALSE == sc);
|
|
|
|
EH_Err:
|
|
if( (STG_E_OLDFORMAT == sc) || (STG_E_INVALIDHEADER == sc) )
|
|
sc = S_FALSE;
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------
|
|
//
|
|
// Function: StgIsStorageFile, public
|
|
//
|
|
// Synopsis: Determines whether the named file is a storage or not
|
|
//
|
|
// Arguments: [pwcsName] - Filename
|
|
//
|
|
// Returns: S_OK, S_FALSE or error codes
|
|
//
|
|
// History: 05-Oct-92 DrewB Created
|
|
//
|
|
//---------------------------------------------------------------
|
|
|
|
|
|
STDAPI StgIsStorageFile(OLECHAR const *pwcsName)
|
|
{
|
|
HANDLE hf;
|
|
SCODE sc;
|
|
|
|
olLog(("--------::In StgIsStorageFile(" OLEFMT ")\n", pwcsName));
|
|
|
|
TRY
|
|
{
|
|
#ifndef OLEWIDECHAR
|
|
if (FAILED(sc = ValidateNameA(pwcsName, _MAX_PATH)))
|
|
#else
|
|
if (FAILED(sc = ValidateNameW(pwcsName, _MAX_PATH)))
|
|
#endif
|
|
return ResultFromScode(sc);
|
|
|
|
#if !defined(UNICODE)
|
|
|
|
// Chicago - call ANSI CreateFile
|
|
|
|
char szName[_MAX_PATH + 1];
|
|
|
|
if (!WideCharToMultiByte(
|
|
AreFileApisANSI() ? CP_ACP : CP_OEMCP,
|
|
0,
|
|
pwcsName,
|
|
-1,
|
|
szName,
|
|
_MAX_PATH + 1,
|
|
NULL,
|
|
NULL))
|
|
return ResultFromScode(STG_E_INVALIDNAME);
|
|
|
|
hf = CreateFileA (
|
|
szName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
#else
|
|
|
|
hf = CreateFile (
|
|
pwcsName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
#endif // !defined(UNICODE)
|
|
|
|
if (hf == INVALID_HANDLE_VALUE)
|
|
return ResultFromScode(STG_SCODE(GetLastError()));
|
|
|
|
sc = StgIsStorageFileHandle( hf, NULL );
|
|
CloseHandle (hf);
|
|
|
|
}
|
|
CATCH(CException, e)
|
|
{
|
|
sc = e.GetErrorCode();
|
|
}
|
|
END_CATCH
|
|
|
|
olLog(("--------::Out StgIsStorageFile(). ret == %lx\n", sc));
|
|
|
|
return(ResultFromScode(sc));
|
|
}
|
|
|
|
//+--------------------------------------------------------------
|
|
//
|
|
// Function: StgIsStorageILockBytes, public
|
|
//
|
|
// Synopsis: Determines whether the ILockBytes is a storage or not
|
|
//
|
|
// Arguments: [plkbyt] - The ILockBytes
|
|
//
|
|
// Returns: S_OK, S_FALSE or error codes
|
|
//
|
|
// History: 05-Oct-92 DrewB Created
|
|
//
|
|
//---------------------------------------------------------------
|
|
|
|
STDAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
|
|
{
|
|
OLETRACEIN((API_StgIsStorageILockBytes, PARAMFMT("plkbyt= %p"), plkbyt));
|
|
|
|
HRESULT hr;
|
|
SCODE sc;
|
|
SStorageFile stgfile;
|
|
ULONG cbRead;
|
|
ULARGE_INTEGER ulOffset;
|
|
|
|
TRY
|
|
{
|
|
if (FAILED(sc = ValidateInterface(plkbyt, IID_ILockBytes)))
|
|
{
|
|
hr = ResultFromScode(sc);
|
|
goto errRtn;
|
|
}
|
|
ULISet32(ulOffset, 0);
|
|
hr = plkbyt->ReadAt(ulOffset, &stgfile, sizeof(stgfile), &cbRead);
|
|
if (FAILED(GetScode(hr)))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
}
|
|
CATCH(CException, e)
|
|
{
|
|
hr = ResultFromScode(e.GetErrorCode());
|
|
goto errRtn;
|
|
}
|
|
END_CATCH
|
|
|
|
if (cbRead == sizeof(stgfile))
|
|
{
|
|
if ((memcmp((void *)stgfile.abSig, SIGSTG, CBSIGSTG) == 0) ||
|
|
(memcmp((void *)stgfile.abSig, SIGSTG_B2, CBSIGSTG_B2) == 0))
|
|
{
|
|
hr = ResultFromScode(S_OK);
|
|
goto errRtn;
|
|
}
|
|
}
|
|
|
|
hr = ResultFromScode(S_FALSE);
|
|
|
|
errRtn:
|
|
OLETRACEOUT((API_StgIsStorageILockBytes, hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+--------------------------------------------------------------
|
|
//
|
|
// Function: StgSetTimes
|
|
//
|
|
// Synopsis: Sets file time stamps
|
|
//
|
|
// Arguments: [lpszName] - Name
|
|
// [pctime] - create time
|
|
// [patime] - access time
|
|
// [pmtime] - modify time
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 05-Oct-92 AlexT Created
|
|
//
|
|
//---------------------------------------------------------------
|
|
|
|
STDAPI StgSetTimes(OLECHAR const *lpszName,
|
|
FILETIME const *pctime,
|
|
FILETIME const *patime,
|
|
FILETIME const *pmtime)
|
|
{
|
|
SCODE sc;
|
|
HANDLE hFile;
|
|
|
|
TRY
|
|
{
|
|
#ifndef OLEWIDECHAR
|
|
sc = ValidateNameA(lpszName, _MAX_PATH);
|
|
#else
|
|
sc = ValidateNameW(lpszName, _MAX_PATH);
|
|
#endif
|
|
if (SUCCEEDED(sc))
|
|
{
|
|
#if !defined(UNICODE) && defined(OLEWIDECHAR)
|
|
//Chicago - call ANSI CreateFile
|
|
char szName[_MAX_PATH];
|
|
|
|
if (!WideCharToMultiByte(
|
|
AreFileApisANSI() ? CP_ACP : CP_OEMCP,
|
|
0,
|
|
lpszName,
|
|
-1,
|
|
szName,
|
|
_MAX_PATH,
|
|
NULL,
|
|
NULL))
|
|
return ResultFromScode(STG_E_INVALIDNAME);
|
|
hFile = CreateFileA(szName, GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
#else
|
|
hFile = CreateFile(lpszName, GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
#endif
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
sc = LAST_STG_SCODE;
|
|
else
|
|
{
|
|
if (!SetFileTime(hFile, (FILETIME *)pctime, (FILETIME *)patime,
|
|
(FILETIME *)pmtime))
|
|
sc = LAST_STG_SCODE;
|
|
CloseHandle(hFile);
|
|
}
|
|
}
|
|
}
|
|
CATCH(CException, e)
|
|
{
|
|
sc = e.GetErrorCode();
|
|
}
|
|
END_CATCH
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
#if DBG==1
|
|
extern "C" unsigned long filestInfoLevel; // File I/O layer of Docfile
|
|
extern "C" unsigned long nffInfoLevel; // NTFS Flat File
|
|
|
|
void
|
|
StgDebugInit()
|
|
{
|
|
GetInfoLevel("filest", &filestInfoLevel, "0x0003");
|
|
GetInfoLevel( "nff", &nffInfoLevel, "0x0003");
|
|
}
|
|
|
|
#endif // DBG==1
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: NormalDllGetClassObject, public
|
|
//
|
|
// Synopsis: Registers any normal Inproc Dll server.
|
|
//
|
|
// Arguments: [refCLSID] Class ID of object to register
|
|
// [pwszDescription] Description to put in the CLSID Key
|
|
// [pwszDllName] Dll where the object's code lives
|
|
// [pwszThreadingModel] Threading Model (i.e. L"both")
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 15-jan-98 BChapman Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#define STRBUFSZ 64
|
|
|
|
STDAPI NormalDllRegisterServer(
|
|
REFCLSID refCLSID,
|
|
WCHAR * pwszDescription,
|
|
WCHAR * pwszDllName,
|
|
WCHAR * pwszThreadingModel)
|
|
{
|
|
|
|
HKEY hkeyCLSID=NULL;
|
|
HKEY hkeyInproc32=NULL;
|
|
DWORD dwDisp=0;
|
|
LONG rc;
|
|
HRESULT sc=S_OK;
|
|
|
|
WCHAR wszCLSID[STRBUFSZ];
|
|
WCHAR wszCLSKey[STRBUFSZ];
|
|
|
|
//--------------------------------------
|
|
// Construct and Open the Class ID key.
|
|
//
|
|
if(0 == StringFromGUID2(refCLSID, wszCLSID, STRBUFSZ))
|
|
olErr( EH_Err, E_UNEXPECTED );
|
|
|
|
wcscpy(wszCLSKey, L"CLSID\\");
|
|
wcscat(wszCLSKey, wszCLSID);
|
|
|
|
rc = RegCreateKeyEx(HKEY_CLASSES_ROOT, wszCLSKey,
|
|
0, _T(""), REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE, NULL,
|
|
&hkeyCLSID, &dwDisp);
|
|
if(ERROR_SUCCESS != rc)
|
|
olErr( EH_Err, REGDB_E_WRITEREGDB );
|
|
|
|
//-----------------------------------------------------
|
|
// Set the description string on the Class ID Key
|
|
//
|
|
rc = RegSetValueEx(hkeyCLSID, _T(""), 0,
|
|
REG_SZ, (BYTE*) pwszDescription,
|
|
sizeof(WCHAR)*(1+wcslen(pwszDescription)) );
|
|
if(ERROR_SUCCESS != rc)
|
|
olErr( EH_Err, REGDB_E_WRITEREGDB );
|
|
|
|
//---------------------------
|
|
// Open the Inproc32 Sub-key.
|
|
//
|
|
rc = RegCreateKeyEx(hkeyCLSID, _T("InprocServer32"),
|
|
0, _T(""), REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE, NULL,
|
|
&hkeyInproc32, &dwDisp);
|
|
if(ERROR_SUCCESS != rc)
|
|
olErr( EH_Err, REGDB_E_WRITEREGDB );
|
|
|
|
//-----------------------------------------
|
|
// Set the DLL name on the Inproc32 Sub-Key
|
|
//
|
|
rc = RegSetValueEx(hkeyInproc32, _T(""), 0,
|
|
REG_SZ, (BYTE*) pwszDllName,
|
|
sizeof(WCHAR)*(1+wcslen(pwszDllName)));
|
|
if(ERROR_SUCCESS != rc)
|
|
olErr( EH_Err, REGDB_E_WRITEREGDB );
|
|
|
|
//------------------------
|
|
// Set the Threading Model
|
|
//
|
|
rc = RegSetValueEx(hkeyInproc32, _T("ThreadingModel"), 0,
|
|
REG_SZ, (BYTE*) pwszThreadingModel,
|
|
sizeof(WCHAR)*(1+wcslen(pwszThreadingModel)));
|
|
if(ERROR_SUCCESS != rc)
|
|
olErr( EH_Err, REGDB_E_WRITEREGDB );
|
|
|
|
EH_Err:
|
|
if(NULL != hkeyCLSID)
|
|
RegCloseKey(hkeyCLSID);
|
|
if(NULL != hkeyInproc32)
|
|
RegCloseKey(hkeyInproc32);
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AddCLSIDToMultiSz, public
|
|
//
|
|
// Synopsis: Add the string form of a Class ID to a MultiSZ registry value.
|
|
//
|
|
// Arguments: [refCLSID] Class ID to register
|
|
// [hkeyStart] An open registry key.
|
|
// [wcszKey] Path to the key reletive to hkeyStart.
|
|
// [wcszValue] Name of the Value under wcszKey.
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 18-jan-98 BChapman Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI AddCLSIDToMultiSz(
|
|
REFCLSID refCLSID,
|
|
HKEY hkeyStart,
|
|
WCHAR* wcszKey,
|
|
WCHAR* wcszValue)
|
|
{
|
|
WCHAR wszCLSID[STRBUFSZ];
|
|
int ccCLSIDstr;
|
|
LONG rc;
|
|
HRESULT sc=S_OK;
|
|
HKEY hkeyKey=NULL;
|
|
|
|
BYTE* p_bytes=NULL;
|
|
WCHAR* p_wsz=NULL;
|
|
DWORD cbData, cbDataNew;
|
|
DWORD dwType;
|
|
|
|
ccCLSIDstr = StringFromGUID2( refCLSID, wszCLSID, STRBUFSZ );
|
|
if( 0 == ccCLSIDstr )
|
|
olErr( EH_Err, E_UNEXPECTED );
|
|
ccCLSIDstr += 1; // +1 for the NULL
|
|
|
|
// Open the Key
|
|
//
|
|
rc = RegOpenKeyEx(hkeyStart,
|
|
wcszKey,
|
|
0,
|
|
KEY_QUERY_VALUE | KEY_SET_VALUE,
|
|
&hkeyKey);
|
|
if( ERROR_SUCCESS != rc )
|
|
olErr( EH_Err, REGDB_E_KEYMISSING );
|
|
|
|
// Size The Buffer,
|
|
// Allocate the buffer,
|
|
// And Read the data.
|
|
//
|
|
cbData = 0;
|
|
cbDataNew = 0;
|
|
rc = RegQueryValueEx( hkeyKey,
|
|
wcszValue,
|
|
0,
|
|
&dwType,
|
|
NULL,
|
|
&cbData );
|
|
if( ERROR_SUCCESS != rc )
|
|
{
|
|
//
|
|
// The value may not exist. In that case we make a new entry.
|
|
// Rather than depend on an exact error code, lets take the "new"
|
|
// path on all failures. We will hit real problems in the "write"
|
|
// phase
|
|
cbData = 1*sizeof(WCHAR); // +1 for the terminating second Null.
|
|
cbDataNew = (ccCLSIDstr + 1) * sizeof(WCHAR);
|
|
olMem( p_bytes = new BYTE[ cbDataNew ] );
|
|
memset( p_bytes, 0, cbDataNew );
|
|
}
|
|
else
|
|
{
|
|
if( REG_MULTI_SZ != dwType )
|
|
olErr( EH_Err, REGDB_E_INVALIDVALUE );
|
|
|
|
// cbData is in units of bytes
|
|
//
|
|
cbDataNew = cbData + ( ccCLSIDstr * sizeof(WCHAR) );
|
|
olMem( p_bytes = new BYTE[ cbDataNew ] );
|
|
memset( p_bytes, 0, cbDataNew );
|
|
rc = RegQueryValueEx( hkeyKey,
|
|
wcszValue,
|
|
0,
|
|
&dwType,
|
|
p_bytes,
|
|
&cbData );
|
|
if( ERROR_SUCCESS != rc )
|
|
olErr( EH_Err, LAST_SCODE );
|
|
}
|
|
|
|
// Check if the Class Id is already present
|
|
//
|
|
p_wsz = (WCHAR*)p_bytes;
|
|
while( L'\0' != *p_wsz)
|
|
{
|
|
if( 0 == wcscmp( p_wsz, wszCLSID ) )
|
|
break;
|
|
|
|
// Advance to the end of the String.
|
|
while( L'\0' != *p_wsz)
|
|
++p_wsz;
|
|
|
|
// Advance to the start of the next String.
|
|
// Or the terminating second null.
|
|
++p_wsz;
|
|
}
|
|
|
|
|
|
// If the Class Id is not already present,
|
|
// Add the Class Id to the list
|
|
// And write it into the Registry
|
|
//
|
|
if( L'\0' == *p_wsz )
|
|
{
|
|
wcscpy( p_wsz, wszCLSID );
|
|
p_wsz[ ccCLSIDstr ] = L'\0'; // Add the Second Null.
|
|
|
|
rc = RegSetValueEx( hkeyKey,
|
|
wcszValue,
|
|
0,
|
|
REG_MULTI_SZ,
|
|
p_bytes,
|
|
cbDataNew );
|
|
if( ERROR_SUCCESS != rc )
|
|
olErr( EH_Err, REGDB_E_WRITEREGDB );
|
|
}
|
|
|
|
EH_Err:
|
|
if( NULL != hkeyKey )
|
|
RegCloseKey( hkeyKey );
|
|
|
|
if( NULL != p_bytes )
|
|
delete[] p_bytes;
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: DllRegisterServer, public
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 15-jan-98 BChpaman Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI Storage32DllRegisterServer(void)
|
|
{
|
|
HRESULT hrAccum=S_OK;
|
|
|
|
return hrAccum;
|
|
}
|