Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

729 lines
20 KiB

//@@@@AUTOBLOCK+============================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// File: medialoc.cpp
//
// Copyright (c) Microsoft Corporation. All Rights Reserved.
//
//@@@@AUTOBLOCK-============================================================;
// MediaLocator.cpp : Implementation of CMediaLocator
#include "stdafx.h"
#include <qeditint.h>
#include <qedit.h>
#include "..\util\dexmisc.h"
#include "MediaLoc.h"
#define STRSAFE_NO_DEPRECATE
#include <strsafe.h>
#define MAX_FILTER_STRING 1024
const long DEFAULT_DIRECTORIES = 8;
const TCHAR * gszRegistryLoc = TEXT("Software\\Microsoft\\ActiveMovie\\MediaLocator");
CMediaLocator::CMediaLocator( )
{
m_bUseLocal = FALSE;
HKEY hKey = NULL;
// create the key just to make sure it's there
//
long Result = RegCreateKeyEx(
HKEY_CURRENT_USER, // key
gszRegistryLoc, // sub key
0, // reserved
NULL, // lpClass
0, // options
KEY_EXECUTE | KEY_QUERY_VALUE,
NULL, // default ACL
&hKey,
NULL ); // disp
if( Result == ERROR_SUCCESS )
{
// go find out if we're supposed to look locally
//
DWORD Size = sizeof( long );
DWORD Type = REG_DWORD;
long UseLocal = 0;
Result = RegQueryValueEx(
hKey,
TEXT("UseLocal"),
0, // reserved
&Type,
(BYTE*) &UseLocal,
&Size );
if( Result == ERROR_SUCCESS )
{
m_bUseLocal = UseLocal;
}
RegCloseKey( hKey );
}
}
/////////////////////////////////////////////////////////////////////////////
// FindMediaFile - try to find the media file using some cacheing mechanism
// Use the registry to hold the caching directories. A return value of S_FALSE
// means the file was replaced with another, a return code of E_FAIL means
// the file couldn't be found anywhere.
/////////////////////////////////////////////////////////////////////////////
//
HRESULT CMediaLocator::FindMediaFile
( BSTR Input, BSTR FilterString, BSTR * pOutput, long ValidateFlags )
{
CheckPointer( pOutput, E_POINTER );
HRESULT hr;
// don't validate the incoming filename exists, since it very well may
// not (that's the point of this class). We *should* be validating the
// file name isn't a printer or something, but this is better left AFTER
// finding the name, than before
hr = ValidateFilenameIsntNULL( Input);
if( FAILED( hr ) ) return hr;
BOOL UseLocal = ( ( ValidateFlags & SFN_VALIDATEF_USELOCAL ) == SFN_VALIDATEF_USELOCAL );
BOOL WantUI = ( ( ValidateFlags & SFN_VALIDATEF_POPUP ) == SFN_VALIDATEF_POPUP );
BOOL WarnReplace = ( ( ValidateFlags & SFN_VALIDATEF_TELLME ) == SFN_VALIDATEF_TELLME );
BOOL DontFind = ( ( ValidateFlags & SFN_VALIDATEF_NOFIND ) == SFN_VALIDATEF_NOFIND );
UseLocal |= m_bUseLocal ;
// reset this now
//
*pOutput = NULL;
// !!! what if the incoming file is not on a disk, like
// 1) On the web
// 2) On external hardware!
USES_CONVERSION;
TCHAR * tInput = W2T( Input );
BOOL FoundFileAsSpecified = FALSE;
HANDLE hcf = CreateFile(
tInput,
GENERIC_READ, // the point is, we're about to see if we can read it. Don't use "0"
FILE_SHARE_READ, // share mode
NULL, // security
OPEN_EXISTING, // creation disposition
0, // flags
NULL );
if( INVALID_HANDLE_VALUE != hcf )
{
FoundFileAsSpecified = TRUE;
CloseHandle( hcf );
}
// if we found the file where the user asked and they didn't specify use local
// then return
//
if( FoundFileAsSpecified )
{
if( !UseLocal )
{
hr = ValidateFilename( Input, MAX_PATH, FALSE );
ASSERT( !FAILED( hr ) );
return hr;
}
else
{
// they specified use local and it is local
//
// !!! this isn't good enough.
if( tInput[0] != '\\' || tInput[1] != '\\' )
{
hr = ValidateFilename( Input, MAX_PATH, FALSE );
ASSERT( !FAILED( hr ) );
return hr;
}
}
}
// cut up the filename into little bits
//
TCHAR Drive[_MAX_DRIVE];
TCHAR Dir[_MAX_DIR];
TCHAR Fname[_MAX_FNAME];
TCHAR Ext[_MAX_EXT];
_tsplitpath( tInput, Drive, Dir, Fname, Ext );
TCHAR tNewFileName[_MAX_PATH];
// can't find nothing
//
if( wcslen( Input ) == 0 ) // safe
{
return E_INVALIDARG;
}
// where did we look last?
//
HKEY hKey = NULL;
long Result = RegOpenKeyEx(
HKEY_CURRENT_USER,
gszRegistryLoc ,
0, // reserved options
KEY_EXECUTE | KEY_SET_VALUE | KEY_QUERY_VALUE,
&hKey );
if( Result != ERROR_SUCCESS )
{
return MAKE_HRESULT( 1, 4, Result );
}
// find out how many cached directories to look in
//
long DirectoryCount = DEFAULT_DIRECTORIES;
DWORD Size = sizeof( long );
DWORD Type = REG_DWORD;
Result = RegQueryValueEx(
hKey,
TEXT("Directories"),
0, // reserved
&Type,
(BYTE*) &DirectoryCount,
&Size );
if( Result != ERROR_SUCCESS )
{
// if we don't have a count, default to something
//
DirectoryCount = DEFAULT_DIRECTORIES;
}
// bound this to something reasonable
if( DirectoryCount > 32 )
{
DirectoryCount = 32;
}
if( DirectoryCount < 1 )
{
DirectoryCount = 1;
}
while( !DontFind )
{
// look in each directory
//
bool foundit = false;
for( long i = 0 ; i < DirectoryCount ; i++ )
{
TCHAR ValueName[256];
wsprintf( ValueName, TEXT("Directory%2.2ld"), i ); // safe, i can't be > 99
TCHAR DirectoryName[256];
Size = sizeof(DirectoryName);
Type = REG_SZ;
Result = RegQueryValueEx(
hKey,
ValueName,
0, // reserved
&Type,
(BYTE*) DirectoryName,
&Size );
if( Result != ERROR_SUCCESS )
{
// didn't find it, must not exist, do the next one
//
continue;
}
// found a directory
// build up a new filename
//
size_t Remaining = _MAX_PATH;
TCHAR * tContinue = NULL;
hr = StringCchCopyEx( tNewFileName, Remaining, DirectoryName, &tContinue, &Remaining, 0 );
if( FAILED( hr ) )
{
continue;
}
hr = StringCchCopyEx( tContinue, Remaining, Fname, &tContinue, &Remaining, 0 );
if( FAILED( hr ) )
{
continue;
}
hr = StringCchCopyEx( tContinue, Remaining, Ext, NULL, NULL, 0 );
if( FAILED( hr ) )
{
continue;
}
// if UseLocal is set, and this directory is on the net, then
// ignore it
//
if( UseLocal )
{
// !!! ugly
if( tNewFileName[0] == '\\' && tNewFileName[1] == '\\' )
{
continue;
}
}
HANDLE h = CreateFile(
tNewFileName,
GENERIC_READ, // access
FILE_SHARE_READ, // share mode
NULL, // security
OPEN_EXISTING, // creation disposition
0, // flags
NULL );
if( INVALID_HANDLE_VALUE == h )
{
// didn't find it, continue
//
continue;
}
// found the directory it was in, break;
//
CloseHandle( h );
foundit = true;
break;
}
// found it!
//
if( foundit )
{
// validate it first
//
hr = ValidateFilename( T2W( tNewFileName ), MAX_PATH, FALSE );
ASSERT( !FAILED( hr ) );
if( SUCCEEDED( hr ) )
{
AddOneToDirectoryCache( hKey, i );
*pOutput = SysAllocString( T2W( tNewFileName ) );
hr = *pOutput ? S_FALSE : E_OUTOFMEMORY;
if( WarnReplace )
{
ShowWarnReplace( Input, *pOutput );
}
}
RegCloseKey( hKey );
hKey = NULL;
return hr;
}
// we didn't find it. :-(
// if we got here, we found it where it was supposed to be, but
// we tried to look for it locally instead. Return we found it.
//
if( FoundFileAsSpecified )
{
hr = ValidateFilename( Input, MAX_PATH, FALSE );
ASSERT( !FAILED( hr ) );
RegCloseKey( hKey );
return hr;
}
if( !UseLocal )
{
break; // out of while loop
}
UseLocal = FALSE;
} // while 1 ( UseLocal will break us out )
// it's REALLY not around!
// if we don't want UI, just signal we couldn't find it
//
if( !WantUI )
{
// we return S_FALSE to signify the file was replaced, and
// a failure code to signify we couldn't find it period.
//
RegCloseKey( hKey );
hKey = NULL;
return E_FAIL;
}
// bring up a UI and try to go find it
//
OPENFILENAME ofn;
ZeroMemory( &ofn, sizeof( ofn ) );
// we need to find two double-nulls in a row if they really specified a
// filter string
TCHAR * tFilter = NULL;
TCHAR ttFilter[MAX_FILTER_STRING];
if( !FAILED( ValidateFilenameIsntNULL( FilterString ) ) )
{
size_t FilterLen = 0;
HRESULT hrLen = StringCchLength( FilterString, MAX_FILTER_STRING, &FilterLen );
if( FilterLen < 2 )
{
return E_INVALIDARG;
}
if( FAILED( hrLen ) )
{
return E_INVALIDARG;
}
// look for two nulls
//
for( int i = 0 ; i < MAX_FILTER_STRING - 1 ; i++ )
{
// found it
//
if( FilterString[i] == 0 && FilterString[i+1] == 0 )
{
break;
}
}
if( i >= MAX_FILTER_STRING - 1 )
{
return E_INVALIDARG;
}
#ifndef UNICODE
// copy it to a shorty string, with two nulls
//
WideCharToMultiByte( CP_ACP, 0, FilterString, i + 2, ttFilter, MAX_FILTER_STRING, NULL, NULL );
#else if
// need to copy both the extra zero's as well, or the filter string will fail
CopyMemory(ttFilter, FilterString, 2*(i+2) );
#endif
// point to it
//
tFilter = ttFilter;
}
// we shouldn't make the return path any longer than max_path either, I think.
// so this code is good.
TCHAR tReturnName[_MAX_PATH];
TCHAR * tEnd = NULL;
size_t tRemaining = 0;
hr = StringCchCopyEx( tReturnName, _MAX_PATH, Fname, &tEnd, &tRemaining, 0 );
if( FAILED( hr ) )
{
return hr;
}
hr = StringCchCopyEx( tEnd, tRemaining, Ext, NULL, NULL, 0 );
if( FAILED( hr ) )
{
return hr;
}
// fashion a title so the user knows what file to find
//
HINSTANCE hinst = _Module.GetModuleInstance( );
TCHAR tErrorMsg[256];
int ReadIn = LoadString( hinst, IDS_CANNOT_FIND_FILE, tErrorMsg, 256 /* characters */ );
TCHAR tTitle[_MAX_PATH + 256]; // it's okay if it's a bit too big
if( ReadIn )
{
tRemaining = _MAX_PATH + 256;
StringCchCopyEx( tTitle, tRemaining, tErrorMsg, &tEnd, &tRemaining, 0 );
StringCchCopyEx( tEnd, tRemaining, tReturnName, NULL, NULL, 0 ); // doesn't matter if it truncates
ofn.lpstrTitle = tTitle;
}
else
{
ReadIn = GetLastError( );
}
ofn.lStructSize = sizeof( ofn );
ofn.hwndOwner = NULL;
ofn.hInstance = _Module.GetModuleInstance( );
ofn.lpstrFilter = tFilter;
ofn.lpstrFile = tReturnName;
ofn.nMaxFile = _MAX_PATH;
ofn.Flags = OFN_ENABLESIZING | OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_LONGNAMES;
long r = GetOpenFileName( &ofn );
if( r == 0 )
{
// not a very good error code, is it?
//
RegCloseKey( hKey );
hKey = NULL;
return E_FAIL;
}
_tsplitpath( ofn.lpstrFile, Drive, Dir, Fname, Ext );
// create a string that is the directory which was found
TCHAR ReplacementPath[_MAX_DRIVE+_MAX_DIR];
StringCchCopy( ReplacementPath, _MAX_DRIVE+_MAX_DIR, Drive ); // safe, Drive can't be over max_drive!
StringCchCat( ReplacementPath, _MAX_DIR, Dir ); // safe
long i = GetLeastUsedDirectory( hKey, DirectoryCount );
ReplaceDirectoryPath( hKey, i, ReplacementPath );
*pOutput = SysAllocString( T2W( ofn.lpstrFile ) );
hr = *pOutput ? S_FALSE : E_OUTOFMEMORY;
RegCloseKey( hKey );
hKey = NULL;
return hr;
}
// sets registry value, called from FindMediaFile
void CMediaLocator::AddOneToDirectoryCache( HKEY hKey, int WhichDirectory )
{
DWORD Size = sizeof( long );
DWORD Type = REG_DWORD;
long UsageCount = 0;
TCHAR ValueName[25];
wsprintf( ValueName, TEXT("Dir%2.2ldUses"), WhichDirectory ); // safe
long Result = RegQueryValueEx(
hKey,
ValueName,
0, // reserved
&Type,
(BYTE*) &UsageCount,
&Size );
if( Result != ERROR_SUCCESS )
{
return;
}
UsageCount++;
RegSetValueEx(
hKey,
ValueName,
0, // reserverd
REG_DWORD,
(BYTE*) &UsageCount,
sizeof( UsageCount ) );
}
int CMediaLocator::GetLeastUsedDirectory( HKEY hKey, int DirectoryCount )
{
long Min = -1;
long WhichDir = 0;
long i;
for( i = 0 ; i < DirectoryCount ; i++ )
{
TCHAR ValueName[25];
wsprintf( ValueName, TEXT("Dir%2.2ldUses"), i ); // safe
DWORD Size = sizeof( long );
DWORD Type = REG_DWORD;
long UsageCount = 0;
long Result = RegQueryValueEx(
hKey,
ValueName,
0, // reserved
&Type,
(BYTE*) &UsageCount,
&Size );
if( Result != ERROR_SUCCESS )
{
// since this key didn't exist yet, it's certainly not
// used, so we can return "i".
//
return i;
}
if( i == 0 )
{
Min = UsageCount;
}
if( UsageCount < Min )
{
Min = UsageCount;
WhichDir = i;
}
} // for
return WhichDir;
}
// sets registry value
void CMediaLocator::ReplaceDirectoryPath( HKEY hKey, int WhichDirectory, TCHAR * Path )
{
// don't stick it in the registry if it's too big
//
if( _tcslen( Path ) > _MAX_PATH )
{
return;
}
TCHAR ValueName[25];
wsprintf( ValueName, TEXT("Directory%2.2ld"), WhichDirectory ); // safe
DWORD Size = sizeof(TCHAR) * ( _tcslen(Path) + 1 ); // safe
RegSetValueEx(
hKey,
ValueName,
0, // reserved
REG_SZ,
(BYTE*) Path,
Size );
// doesn't matter if it bombs
long UsageCount = 0;
wsprintf( ValueName, TEXT("Dir%2.2ldUses"), WhichDirectory ); // safe
RegSetValueEx(
hKey,
ValueName,
0, // reserverd
REG_DWORD,
(BYTE*) &UsageCount,
sizeof( UsageCount ) );
// doesn't matter if it bombs
}
STDMETHODIMP CMediaLocator::AddFoundLocation( BSTR Dir )
{
// where did we look last?
//
HKEY hKey = NULL;
long Result = RegOpenKeyEx(
HKEY_CURRENT_USER,
gszRegistryLoc ,
0, // reserved options
KEY_READ | KEY_WRITE, // access
&hKey );
if( Result != ERROR_SUCCESS )
{
return MAKE_HRESULT( 1, 4, Result );
}
// find out how many cached directories to look in
//
long DirectoryCount = DEFAULT_DIRECTORIES;
DWORD Size = sizeof( long );
DWORD Type = REG_DWORD;
Result = RegQueryValueEx(
hKey,
TEXT("Directories"),
0, // reserved
&Type,
(BYTE*) &DirectoryCount,
&Size );
if( Result != ERROR_SUCCESS )
{
// if we don't have a count, default to something
//
DirectoryCount = DEFAULT_DIRECTORIES;
}
// bound it
if( ( DirectoryCount < 1 ) || ( DirectoryCount > 32 ) )
{
DirectoryCount = DEFAULT_DIRECTORIES;
}
USES_CONVERSION;
TCHAR * tDir = W2T( Dir );
long i = GetLeastUsedDirectory( hKey, DirectoryCount );
if( ( i < 0 ) || ( i > 31 ) )
{
RegCloseKey( hKey );
return NOERROR;
}
ReplaceDirectoryPath( hKey, i, tDir );
RegCloseKey( hKey );
return NOERROR;
}
void CMediaLocator::ShowWarnReplace( TCHAR * pOriginal, TCHAR * pReplaced )
{
CAutoLock Lock( &m_Lock );
HINSTANCE h = _Module.GetModuleInstance( );
// these will (correctly) truncate the incoming strings if they're too long
// so nothing needs done here, we can even ignore the return codes
// from the below
StringCchCopy( CMediaLocator::szShowWarnOriginal, _MAX_PATH, pOriginal );
StringCchCopy( CMediaLocator::szShowWarnReplaced, _MAX_PATH, pReplaced );
HWND hDlg = CreateDialog( h, MAKEINTRESOURCE( IDD_MEDLOC_DIALOG ), NULL, DlgProc );
if( !hDlg )
{
return;
}
static int cx = 0;
static int cy = 0;
cx += 20;
cy += 15;
if( cx > 600 ) cx -= 600;
if( cy > 400 ) cy -= 400;
ShowWindow( hDlg, SW_SHOW );
SetWindowPos( hDlg, NULL, cx, cy, 0, 0, SWP_NOSIZE | SWP_NOZORDER );
USES_CONVERSION;
TCHAR * tOriginal = W2T( CMediaLocator::szShowWarnOriginal );
TCHAR * tReplaced = W2T( CMediaLocator::szShowWarnReplaced );
SetDlgItemText( hDlg, IDC_ORIGINAL, tOriginal );
SetDlgItemText( hDlg, IDC_FOUND, tReplaced );
DWORD ThreadId = 0;
HANDLE NewThread = CreateThread( NULL, 0, ThreadProc, (LPVOID) hDlg, 0, &ThreadId );
if( !NewThread )
{
EndDialog( hDlg, TRUE );
}
else
{
SetThreadPriority( NewThread, THREAD_PRIORITY_BELOW_NORMAL );
}
// by the time this dialog call gets back, it will have used the values
// stored in the static vars and they are free to be used again
}
TCHAR CMediaLocator::szShowWarnOriginal[_MAX_PATH];
TCHAR CMediaLocator::szShowWarnReplaced[_MAX_PATH];
INT_PTR CALLBACK CMediaLocator::DlgProc( HWND h, UINT i, WPARAM w, LPARAM l )
{
switch( i )
{
case WM_INITDIALOG:
{
return TRUE;
}
}
return FALSE;
}
DWORD WINAPI CMediaLocator::ThreadProc( LPVOID lpParam )
{
Sleep( 3000 );
EndDialog( (HWND) lpParam, TRUE );
return 0;
}