1439 lines
36 KiB
C++
1439 lines
36 KiB
C++
/*
|
|
** Command & Conquer Renegade(tm)
|
|
** Copyright 2025 Electronic Arts Inc.
|
|
**
|
|
** This program is free software: you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation, either version 3 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
|
|
***********************************************************************************************
|
|
* *
|
|
* Project Name : LevelEdit *
|
|
* *
|
|
* $Archive:: /Commando/Code/Tools/LevelEdit/VSSClass.cpp $*
|
|
* *
|
|
* Author:: Patrick Smith *
|
|
* *
|
|
* $Modtime:: 1/29/02 3:16p $*
|
|
* *
|
|
* $Revision:: 13 $*
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "vssclass.h"
|
|
#include "utils.h"
|
|
#include "filemgr.h"
|
|
#include "oleauto.h"
|
|
#include "afxdisp.h"
|
|
#include "rawfile.h"
|
|
|
|
|
|
typedef struct tagVSS_ERROR
|
|
{
|
|
HRESULT hresult;
|
|
LPCTSTR description;
|
|
} VSS_ERROR;
|
|
|
|
VSS_ERROR _ErrorArray[] =
|
|
{
|
|
{ -2147164975, "You cannot change the Admin name or access privileges" },
|
|
{ -2147166139, "Invalid DOS path: < >" },
|
|
{ -2147166373, "File < > is currently checked out by < >" },
|
|
{ -2147166374, "You currently have file < > checked out" },
|
|
{ -2147166386, "Cannot delete the root project" },
|
|
{ -2147166391, "You do not have access rights to < >" },
|
|
{ -2147166398, "Cannot move the root project" },
|
|
{ -2147166404, "File < > is not checked out" },
|
|
{ -2147166405, "File < > is not shared by any other projects" },
|
|
{ -2147166411, "Cannot Rename the root project" },
|
|
{ -2147166417, "A project cannot be shared under a descendant." },
|
|
{ -2147166418, "File < > is already shared by this project" },
|
|
{ -2147166424, "The SourceSafe database has been locked by the Administrator." },
|
|
{ -2147166519, "Invalid password" },
|
|
{ -2147166521, "Cannot delete the Admin user" },
|
|
{ -2147166522, "Permission denied " },
|
|
{ -2147166525, "User ""< >"" already exists" },
|
|
{ -2147166526, "User ""< >"" not found " },
|
|
{ -2147166572, "An item with the name < > already exists" },
|
|
{ -2147166574, "You can not move a project under itself" },
|
|
{ -2147166583, "Version not found" },
|
|
{ -2147167977, "The SourceSafe database path < > does not exist. Please select another database." },
|
|
{ -2147210887, "This command only works on projects." },
|
|
{ -2147210888, "This command only works on files." },
|
|
{ -2147352566, "Invalid access code (bad parameter)*" }
|
|
};
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Sys_String_To_ANSI
|
|
//
|
|
LPTSTR
|
|
Sys_String_To_ANSI (BSTR bstr)
|
|
{
|
|
int len = ::SysStringLen (bstr);
|
|
|
|
TCHAR *ansi_string = new TCHAR[len + 1];
|
|
ASSERT(ansi_string != NULL);
|
|
|
|
// Convert the BSTR to ANSI using the ANSI code page
|
|
::WideCharToMultiByte (CP_ACP,
|
|
0,
|
|
bstr,
|
|
len,
|
|
ansi_string,
|
|
len + 1,
|
|
NULL,
|
|
NULL);
|
|
|
|
// Ensure the new string is NULL terminated
|
|
ansi_string[len] = 0;
|
|
|
|
// Return a pointer to the ANSI string
|
|
return ansi_string;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Alloc_Sys_String
|
|
//
|
|
BSTR
|
|
Alloc_Sys_String (LPCTSTR string)
|
|
{
|
|
BSTR sys_string = NULL;
|
|
|
|
if (string != NULL) {
|
|
|
|
// Copy the ascii format string to a wide-character string
|
|
WCHAR *pwide_string = new WCHAR [::lstrlen (string) + 1];
|
|
WCHAR *ptemp_string = pwide_string;
|
|
while (*string) {
|
|
*ptemp_string++ = (WCHAR)*string++;
|
|
}
|
|
*ptemp_string = WCHAR('\0');
|
|
|
|
// Allocate a system-string (COM-safe) from the wide-character string.
|
|
sys_string = ::SysAllocString (pwide_string);
|
|
|
|
// Free the wide-character string we allocated earlier
|
|
delete [] pwide_string;
|
|
pwide_string = NULL;
|
|
}
|
|
|
|
// Return the system string
|
|
return sys_string;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// IDispatch_Get_Property
|
|
//
|
|
bool
|
|
IDispatch_Get_Property
|
|
(
|
|
LPDISPATCH pdispatch,
|
|
DISPID dispid,
|
|
VARIANT *presult
|
|
)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
// Params OK?
|
|
ASSERT (pdispatch != NULL);
|
|
if (pdispatch != NULL) {
|
|
|
|
// Get this property w/o passing any args
|
|
DISPPARAMS no_args = {NULL, NULL, 0, 0};
|
|
retval = SUCCEEDED (pdispatch->Invoke (dispid,
|
|
IID_NULL,
|
|
NULL,
|
|
DISPATCH_PROPERTYGET,
|
|
&no_args,
|
|
presult,
|
|
NULL,
|
|
NULL));
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// IDispatch_Get_Property
|
|
//
|
|
bool
|
|
IDispatch_Get_Property
|
|
(
|
|
LPDISPATCH pdispatch,
|
|
DISPID dispid,
|
|
VARIANT &var_arg,
|
|
VARIANT *presult
|
|
)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
// Params OK?
|
|
ASSERT (pdispatch != NULL);
|
|
if (pdispatch != NULL) {
|
|
|
|
// Fill in the dispatch-params structure with our single param
|
|
DISPPARAMS args = {NULL, NULL, 0, 0};
|
|
args.rgvarg = &var_arg;
|
|
args.cArgs = 1;
|
|
|
|
// Get this property an pass in the single arguement
|
|
EXCEPINFO excep_info = { 0 };
|
|
retval = SUCCEEDED (pdispatch->Invoke (dispid,
|
|
IID_NULL,
|
|
NULL,
|
|
DISPATCH_PROPERTYGET,
|
|
&args,
|
|
presult,
|
|
&excep_info,
|
|
NULL));
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_VSS_Interface
|
|
//
|
|
void
|
|
VSSClass::Get_VSS_Interface (void)
|
|
{
|
|
if (m_pIVSSDatabase == NULL) {
|
|
|
|
// Attempt to create an instance of the VSS Database interface
|
|
LPUNKNOWN punknown = NULL;
|
|
HRESULT hresult = ::CoCreateInstance (CLSID_VSSDatabase,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IVSSDatabase,
|
|
(LPVOID *)&punknown);
|
|
if (SUCCEEDED (hresult)) {
|
|
|
|
// Get a pointer to the 'newest' interface we know about
|
|
punknown->QueryInterface (IID_IVSSDatabase, (LPVOID *)&m_pIVSSDatabase);
|
|
|
|
// Release our hold on the original IUnknown interface
|
|
COM_RELEASE (punknown);
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Open_Database
|
|
//
|
|
bool
|
|
VSSClass::Open_Database
|
|
(
|
|
LPCTSTR ini_filename,
|
|
LPCTSTR username,
|
|
LPCTSTR password
|
|
)
|
|
{
|
|
// Make sure we have an interface to work with
|
|
Get_VSS_Interface ();
|
|
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
m_bReadOnly = TRUE;
|
|
ASSERT (m_pIVSSDatabase != NULL);
|
|
if (m_pIVSSDatabase != NULL) {
|
|
|
|
// Convert the string params to COM-safe system strings
|
|
BSTR bstr_filename = ::Alloc_Sys_String (ini_filename);
|
|
BSTR bstr_username = ::Alloc_Sys_String (username != NULL ? username : "");
|
|
BSTR bstr_password = ::Alloc_Sys_String (password != NULL ? password : "");
|
|
|
|
// Ask VSS to open this database
|
|
retval = SUCCEEDED (m_pIVSSDatabase->Open (bstr_filename, bstr_username, bstr_password));
|
|
if (retval) {
|
|
|
|
//
|
|
// Determine if the user is read-only
|
|
//
|
|
IVSSUser *user = NULL;
|
|
if (SUCCEEDED (m_pIVSSDatabase->get_User (bstr_username, &user))) {
|
|
VARIANT_BOOL readonly = 0;
|
|
user->get_ReadOnly (&readonly);
|
|
m_bReadOnly = (readonly != 0);
|
|
COM_RELEASE (user);
|
|
}
|
|
|
|
//
|
|
// Set the working directory
|
|
//
|
|
|
|
/*IVSSItem *root_item = Get_VSS_Item ("$/");
|
|
if (root_item != NULL) {
|
|
|
|
LPCTSTR local_path = ::Get_File_Mgr ()->Get_Base_Path ();
|
|
BSTR bstr_local_path = ::Alloc_Sys_String (local_path);
|
|
HRESULT result = root_item->put_LocalSpec (bstr_local_path);
|
|
ASSERT (SUCCEEDED (result));
|
|
::SysFreeString (bstr_local_path);
|
|
|
|
COM_RELEASE (root_item);
|
|
}*/
|
|
}
|
|
|
|
// Free the system strings we allocated earlier
|
|
::SysFreeString (bstr_filename);
|
|
::SysFreeString (bstr_username);
|
|
::SysFreeString (bstr_password);
|
|
}
|
|
|
|
// Free our inteface pointer if the function wasn't successfull
|
|
if (retval == false) {
|
|
COM_RELEASE (m_pIVSSDatabase);
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_VSS_Item_From_Local_Path
|
|
//
|
|
IVSSItem *
|
|
VSSClass::Get_VSS_Item_From_Local_Path (LPCTSTR local_filename)
|
|
{
|
|
// Assume failure
|
|
IVSSItem *pitem = NULL;
|
|
|
|
ASSERT (m_pIVSSDatabase != NULL);
|
|
ASSERT (local_filename != NULL);
|
|
|
|
// State OK?
|
|
if ((m_pIVSSDatabase != NULL) &&
|
|
(local_filename != NULL)) {
|
|
|
|
// Lookup the relative path
|
|
TCHAR vss_path[MAX_PATH];
|
|
CString rel_path = ::Get_File_Mgr ()->Make_Relative_Path (local_filename);
|
|
::wsprintf (vss_path, "$/%s", (LPCTSTR)rel_path);
|
|
|
|
// Now, lookup the VSS item
|
|
pitem = Get_VSS_Item (vss_path);
|
|
}
|
|
|
|
// Return a pointer to the IVSSItem interface
|
|
return pitem;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_VSS_Item
|
|
//
|
|
IVSSItem *
|
|
VSSClass::Get_VSS_Item (LPCTSTR vss_path)
|
|
{
|
|
// Assume failure
|
|
IVSSItem *pitem = NULL;
|
|
|
|
ASSERT (m_pIVSSDatabase != NULL);
|
|
ASSERT (vss_path != NULL);
|
|
|
|
// State OK?
|
|
if ((m_pIVSSDatabase != NULL) &&
|
|
(vss_path != NULL)) {
|
|
|
|
// Convert the ascii string to a COM-safe BSTR
|
|
BSTR bstr_vss_path = ::Alloc_Sys_String (vss_path);
|
|
|
|
/*VARIANT var_arg;
|
|
var_arg.vt = VT_BSTR;
|
|
var_arg.bstrVal = bstr_vss_path;
|
|
VARIANT result = { 0 };
|
|
|
|
// Use the IDispatch interface to get the VSSItem property
|
|
bool success = ::IDispatch_Get_Property (m_pIVSSDatabase,
|
|
0x00000006,
|
|
var_arg,
|
|
&result); */
|
|
|
|
HRESULT result = m_pIVSSDatabase->get_VSSItem (bstr_vss_path, 0, &pitem);
|
|
if (FAILED (result)) {
|
|
pitem = NULL;
|
|
}
|
|
|
|
// Was the property-get successful?
|
|
/*if (success) {
|
|
|
|
// The IVSSItem pointer should be passed back in the result
|
|
pitem = (IVSSItem *)result.ppdispVal;
|
|
}*/
|
|
|
|
// Free the system string we allocated earlier
|
|
::SysFreeString (bstr_vss_path);
|
|
}
|
|
|
|
// Return a pointer to the IVSSItem interface
|
|
return pitem;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Does_File_Exist
|
|
//
|
|
bool
|
|
VSSClass::Does_File_Exist (LPCTSTR local_filename)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
// Get a pointer to this 'item' inside the VSS database.
|
|
IVSSItem *pitem = Get_VSS_Item_From_Local_Path (local_filename);
|
|
|
|
// If we successfully got the VSS item, then it exists in the DB
|
|
if (pitem != NULL) {
|
|
retval = true;
|
|
|
|
// Release our hold on the item
|
|
COM_RELEASE (pitem);
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Type
|
|
//
|
|
VSSItemType
|
|
VSSClass::Get_Type (LPCTSTR local_filename)
|
|
{
|
|
VSSItemType type = VSSITEM_FILE;
|
|
|
|
// Get a pointer to this 'item' inside the VSS database.
|
|
IVSSItem *pitem = Get_VSS_Item_From_Local_Path (local_filename);
|
|
ASSERT (pitem != NULL);
|
|
if (pitem != NULL) {
|
|
int temp = 0;
|
|
pitem->get_Type (&temp);
|
|
type = (VSSItemType)temp;
|
|
|
|
// Release our hold on the item
|
|
COM_RELEASE (pitem);
|
|
}
|
|
|
|
// Return the type (either project or file)
|
|
return type;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get
|
|
//
|
|
bool
|
|
VSSClass::Get (LPCTSTR local_filename)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
//
|
|
// If this 'file' is a directory, then get files recursively, otherwise
|
|
// simply 'get' the desired file.
|
|
//
|
|
if (Get_Type (local_filename) == VSSITEM_PROJECT) {
|
|
retval = Get_Subproject (local_filename);
|
|
} else {
|
|
|
|
// Get a pointer to this 'item' inside the VSS database.
|
|
IVSSItem *pitem = Get_VSS_Item_From_Local_Path (local_filename);
|
|
ASSERT (pitem != NULL);
|
|
if (pitem != NULL) {
|
|
|
|
// Do the actual file 'get' from VSS.
|
|
retval = Get (local_filename, pitem);
|
|
COM_RELEASE (pitem);
|
|
}
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get
|
|
//
|
|
bool
|
|
VSSClass::Get
|
|
(
|
|
LPCTSTR local_filename,
|
|
IVSSItem *pitem
|
|
)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
// Params OK?
|
|
ASSERT (pitem != NULL);
|
|
if (pitem != NULL) {
|
|
|
|
if (Get_File_Status (local_filename, NULL, 0, pitem) != VSSFILE_CHECKEDOUT_ME) {
|
|
|
|
// Convert the ascii string to a COM-safe BSTR
|
|
BSTR bstr_filename = ::Alloc_Sys_String (local_filename);
|
|
|
|
//
|
|
// Get the file
|
|
//
|
|
VARIANT_BOOL is_different = 0;
|
|
HRESULT hresult = pitem->get_IsDifferent (bstr_filename, &is_different);
|
|
if (!SUCCEEDED (hresult) || (is_different != 0)) {
|
|
retval = SUCCEEDED (pitem->Get (&bstr_filename, VSSFLAG_TIMEMOD | VSSFLAG_REPREPLACE));
|
|
}
|
|
|
|
// Free the system string we allocated earlier
|
|
::SysFreeString (bstr_filename);
|
|
|
|
} else {
|
|
retval = true;
|
|
}
|
|
|
|
//
|
|
// Only do the 'get' if the vss-version and local versions are different.
|
|
//
|
|
/*VARIANT_BOOL is_different = 0;
|
|
HRESULT hresult = pitem->get_IsDifferent (bstr_filename, &is_different);
|
|
if (!SUCCEEDED (hresult) || (is_different != 0)) {
|
|
|
|
// Get the last mod time of the version in VSS
|
|
SYSTEMTIME vss_file_time = { 0 };
|
|
if (Get_File_Date (pitem, vss_file_time)) {
|
|
|
|
// Get the last mod time of the local version
|
|
FILETIME local_file_time = { 0 };
|
|
Get_File_Time (local_filename, NULL, NULL, &local_file_time);
|
|
|
|
//
|
|
// Should this file be overwritten?
|
|
//
|
|
CTime vss_time (vss_file_time);
|
|
CTime local_time (local_file_time);
|
|
if (vss_time > local_time) {
|
|
retval = SUCCEEDED (pitem->Get (&bstr_filename, VSSFLAG_TIMEMOD | VSSFLAG_REPREPLACE));
|
|
}
|
|
}
|
|
}*/
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Subproject
|
|
//
|
|
bool
|
|
VSSClass::Get_Subproject (LPCTSTR local_filename)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
// Get a pointer to this 'item' inside the VSS database.
|
|
IVSSItem *pitem = Get_VSS_Item_From_Local_Path (local_filename);
|
|
|
|
// Did we succesfully get the VSS item?
|
|
ASSERT (pitem != NULL);
|
|
if (pitem != NULL) {
|
|
|
|
Get_Recursive (local_filename, pitem);
|
|
retval = true;
|
|
|
|
// Convert the ascii string to a COM-safe BSTR
|
|
//BSTR bstr_filename = ::Alloc_Sys_String (::Get_File_Mgr ()->Make_Full_Path (local_filename));
|
|
|
|
// Ask the VSS interface to recursively 'get' this file for us
|
|
//retval = SUCCEEDED (pitem->Get (&bstr_filename, VSSFLAG_TIMEMOD | VSSFLAG_RECURSYES));
|
|
|
|
// Free the system string we allocated earlier
|
|
//::SysFreeString (bstr_filename);
|
|
|
|
// Release our hold on the item
|
|
COM_RELEASE (pitem);
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Check_Out
|
|
//
|
|
bool
|
|
VSSClass::Check_Out (LPCTSTR local_filename, bool get_locally)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
// Get a pointer to this 'item' inside the VSS database.
|
|
IVSSItem *pitem = Get_VSS_Item_From_Local_Path (local_filename);
|
|
|
|
// Did we succesfully get the VSS item?
|
|
ASSERT (pitem != NULL);
|
|
if (pitem != NULL) {
|
|
|
|
// Convert the ascii string to a COM-safe BSTR
|
|
BSTR bstr_filename = ::Alloc_Sys_String (local_filename);
|
|
|
|
// Ask the VSS interface to 'checkout' this file for us
|
|
retval = SUCCEEDED (pitem->Checkout (NULL, bstr_filename, (get_locally ? VSSFLAG_TIMEMOD : VSSFLAG_GETNO) | VSSFLAG_CHKEXCLUSIVENO));
|
|
|
|
// Free the system string we allocated earlier
|
|
::SysFreeString (bstr_filename);
|
|
|
|
// Release our hold on the item
|
|
COM_RELEASE (pitem);
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Check_In
|
|
//
|
|
bool
|
|
VSSClass::Check_In
|
|
(
|
|
LPCTSTR local_filename,
|
|
LPCTSTR comment
|
|
)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
// Get a pointer to this 'item' inside the VSS database.
|
|
IVSSItem *pitem = Get_VSS_Item_From_Local_Path (local_filename);
|
|
|
|
// Did we succesfully get the VSS item?
|
|
ASSERT (pitem != NULL);
|
|
if (pitem != NULL) {
|
|
|
|
// Convert the ascii string to a COM-safe BSTR
|
|
BSTR bstr_filename = ::Alloc_Sys_String (local_filename);
|
|
BSTR bstr_comment = (comment != NULL) ? ::Alloc_Sys_String (comment) : NULL;
|
|
|
|
// Ask the VSS interface to 'Checkin' this file for us
|
|
retval = SUCCEEDED (pitem->Checkin (bstr_comment, bstr_filename, VSSFLAG_CMPCHKSUM | VSSFLAG_RECURSNO | VSSFLAG_UPDUPDATE));
|
|
|
|
// Free the system strings we allocated earlier
|
|
::SysFreeString (bstr_filename);
|
|
if (bstr_comment) {
|
|
::SysFreeString (bstr_filename);
|
|
}
|
|
|
|
// Release our hold on the item
|
|
COM_RELEASE (pitem);
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Add_File
|
|
//
|
|
bool
|
|
VSSClass::Add_File
|
|
(
|
|
LPCTSTR local_filename,
|
|
LPCTSTR comment
|
|
)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
if (Build_Tree (local_filename)) {
|
|
|
|
TCHAR parent_dir[MAX_PATH];
|
|
::lstrcpy (parent_dir, ::Strip_Filename_From_Path (local_filename));
|
|
|
|
// Get a pointer to this item's parent inside the VSS database.
|
|
IVSSItem *pitem = Get_VSS_Item_From_Local_Path (parent_dir);
|
|
|
|
// Did we succesfully get the VSS item?
|
|
ASSERT (pitem != NULL);
|
|
if (pitem != NULL) {
|
|
|
|
// Convert the ascii string to a COM-safe BSTR
|
|
BSTR bstr_filename = ::Alloc_Sys_String (local_filename);
|
|
BSTR bstr_comment = (comment != NULL) ? ::Alloc_Sys_String (comment) : NULL;
|
|
|
|
// Ask the VSS interface to add this file for us
|
|
IVSSItem *pnew_item = NULL;
|
|
retval = SUCCEEDED (pitem->Add (bstr_filename, bstr_comment, 0, &pnew_item));
|
|
|
|
// Free the system strings we allocated earlier
|
|
::SysFreeString (bstr_filename);
|
|
if (bstr_comment) {
|
|
::SysFreeString (bstr_filename);
|
|
}
|
|
|
|
// Release our hold on these items
|
|
COM_RELEASE (pitem);
|
|
COM_RELEASE (pnew_item);
|
|
}
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Build_Tree
|
|
//
|
|
bool
|
|
VSSClass::Build_Tree (LPCTSTR local_filename)
|
|
{
|
|
// Assume failure
|
|
bool retval = true;
|
|
|
|
// Create a relative path to use
|
|
CString rel_path = ::Get_File_Mgr ()->Make_Relative_Path (local_filename);
|
|
|
|
// Generate a list of folders from the path
|
|
CString *pfolder_list = NULL;
|
|
int count = ::Build_List_From_String (::Strip_Filename_From_Path (rel_path), "\\", &pfolder_list);
|
|
|
|
// Loop through all the folders in the path and make sure they
|
|
// exist in VSS
|
|
CString vss_path = "$";
|
|
CString parent = "$";
|
|
for (int ifolder = 0; (ifolder < count) && retval; ifolder ++) {
|
|
|
|
// See if this path exists in the VSS database
|
|
vss_path += CString ("\\") + pfolder_list[ifolder];
|
|
IVSSItem *pitem = Get_VSS_Item (vss_path);
|
|
if (pitem == NULL) {
|
|
|
|
// Get a pointer to the parent so we can create a new folder
|
|
pitem = Get_VSS_Item (parent + CString ("\\"));
|
|
if (pitem != NULL) {
|
|
|
|
// Convert the ascii string to a COM-safe BSTR
|
|
BSTR bstr_foldername = ::Alloc_Sys_String (pfolder_list[ifolder]);
|
|
|
|
// Ask the VSS interface to add this folder for us
|
|
IVSSItem *pfolder = NULL;
|
|
retval &= (bool)SUCCEEDED (pitem->NewSubproject (bstr_foldername, NULL, &pfolder));
|
|
|
|
// Free any memory we allocated
|
|
::SysFreeString (bstr_foldername);
|
|
COM_RELEASE (pfolder);
|
|
}
|
|
}
|
|
|
|
COM_RELEASE (pitem);
|
|
parent += CString ("\\") + pfolder_list[ifolder];
|
|
}
|
|
|
|
// Free the list
|
|
SAFE_DELETE_ARRAY (pfolder_list);
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Undo_Check_Out
|
|
//
|
|
bool
|
|
VSSClass::Undo_Check_Out (LPCTSTR local_filename)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
// Get a pointer to this 'item' inside the VSS database.
|
|
IVSSItem *pitem = Get_VSS_Item_From_Local_Path (local_filename);
|
|
|
|
// Did we succesfully get the VSS item?
|
|
ASSERT (pitem != NULL);
|
|
if (pitem != NULL) {
|
|
|
|
// Convert the ascii string to a COM-safe BSTR
|
|
BSTR bstr_filename = ::Alloc_Sys_String (local_filename);
|
|
|
|
// Ask the VSS interface to undo our 'checkout' on this file for us
|
|
retval = SUCCEEDED (pitem->UndoCheckout (bstr_filename, 0));
|
|
|
|
// Free the system string we allocated earlier
|
|
::SysFreeString (bstr_filename);
|
|
|
|
// Release our hold on the item
|
|
COM_RELEASE (pitem);
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Destroy
|
|
//
|
|
bool
|
|
VSSClass::Destroy (LPCTSTR local_filename)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
// Get a pointer to this 'item' inside the VSS database.
|
|
IVSSItem *pitem = Get_VSS_Item_From_Local_Path (local_filename);
|
|
|
|
// Did we succesfully get the VSS item?
|
|
ASSERT (pitem != NULL);
|
|
if (pitem != NULL) {
|
|
|
|
// Ask the VSS interface to completely destroy this file for us
|
|
retval = SUCCEEDED (pitem->Destroy ());
|
|
|
|
// Release our hold on the item
|
|
COM_RELEASE (pitem);
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_File_Version
|
|
//
|
|
long
|
|
VSSClass::Get_File_Version (LPCTSTR local_filename)
|
|
{
|
|
long version = 0L;
|
|
|
|
// Get a pointer to this 'item' inside the VSS database.
|
|
IVSSItem *pitem = Get_VSS_Item_From_Local_Path (local_filename);
|
|
|
|
// Did we succesfully get the VSS item?
|
|
ASSERT (pitem != NULL);
|
|
if (pitem != NULL) {
|
|
|
|
// Get the version number for this item
|
|
VARIANT result = { 0 };
|
|
::IDispatch_Get_Property (pitem, 0x00000008, &result);
|
|
|
|
// Pass the result back to the caller
|
|
version = result.lVal;
|
|
|
|
// Release our hold on the item
|
|
COM_RELEASE (pitem);
|
|
}
|
|
|
|
// Return the version ID
|
|
return version;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Is_File_Different
|
|
//
|
|
bool
|
|
VSSClass::Is_File_Different (LPCTSTR local_filename)
|
|
{
|
|
bool different = false;
|
|
|
|
// Get a pointer to this 'item' inside the VSS database.
|
|
IVSSItem *pitem = Get_VSS_Item_From_Local_Path (local_filename);
|
|
|
|
// Did we succesfully get the VSS item?
|
|
ASSERT (pitem != NULL);
|
|
if (pitem != NULL) {
|
|
|
|
// Convert the ansi string to a system string
|
|
BSTR bstr_filename = ::Alloc_Sys_String (local_filename);
|
|
|
|
VARIANT var_arg = { 0 };
|
|
var_arg.vt = VT_BSTR;
|
|
var_arg.bstrVal = bstr_filename;
|
|
|
|
// Ask VSS if the local and checked-in copy are different
|
|
VARIANT result = { 0 };
|
|
::IDispatch_Get_Property (pitem, 0x00000010, var_arg, &result);
|
|
|
|
// Convert the COM-bool to a C++ bool
|
|
different = (result.boolVal == 0 ? false : true);
|
|
|
|
// Free the system strings we allocated earlier
|
|
::SysFreeString (bstr_filename);
|
|
|
|
// Release our hold on the item
|
|
COM_RELEASE (pitem);
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return different;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_File_Date
|
|
//
|
|
bool
|
|
VSSClass::Get_File_Date
|
|
(
|
|
//LPCTSTR local_filename,
|
|
IVSSItem *pitem,
|
|
SYSTEMTIME &system_time
|
|
)
|
|
{
|
|
// Params OK?
|
|
ASSERT (pitem != NULL);
|
|
if (pitem != NULL) {
|
|
|
|
// Determine which version number we want the date for.
|
|
long current_ver_num = 0;
|
|
pitem->get_VersionNumber (¤t_ver_num);
|
|
|
|
//
|
|
// Get the 'versions' list for this item
|
|
//
|
|
IVSSVersions *pversions = NULL;
|
|
HRESULT hresult = pitem->get_Versions (VSSFLAG_HISTIGNOREFILES, &pversions);
|
|
if (SUCCEEDED (hresult) && (pversions != NULL)) {
|
|
|
|
//
|
|
// Get the version enumerator for this item
|
|
//
|
|
IUnknown *penum_variant = NULL;
|
|
HRESULT hresult = pversions->_NewEnum (&penum_variant);
|
|
if (SUCCEEDED (hresult)) {
|
|
|
|
//
|
|
// Convert the IUnknown version enumerator to a standard
|
|
// VARIANT enumerator.
|
|
//
|
|
IEnumVARIANT *pversion_enum = NULL;
|
|
hresult = penum_variant->QueryInterface (IID_IEnumVARIANT, (LPVOID *)&pversion_enum);
|
|
if (SUCCEEDED (hresult) && (pversion_enum != NULL)) {
|
|
|
|
//
|
|
// Loop through all the versions until we've found the right one.
|
|
//
|
|
bool found = false;
|
|
VARIANT version_info = { 0 };
|
|
while ((pversion_enum->Next (1, &version_info, NULL) == S_OK) && !found) {
|
|
|
|
IVSSVersionOld *pversion = (IVSSVersionOld *)version_info.pdispVal;
|
|
if (pversion != NULL) {
|
|
|
|
// Get this version's number
|
|
long ver_num = 0L;
|
|
pversion->get_VersionNumber (&ver_num);
|
|
|
|
// Is this the version we were looking for?
|
|
if (ver_num == current_ver_num) {
|
|
|
|
// Get the date from the version
|
|
DATE file_date = { 0 };
|
|
pversion->get_Date (&file_date);
|
|
|
|
// Convert the OLE date to a SYSTEMTIME structure
|
|
COleDateTime date_obj (file_date);
|
|
date_obj.GetAsSystemTime (system_time);
|
|
|
|
// Success!
|
|
found = true;
|
|
}
|
|
|
|
COM_RELEASE (pversion);
|
|
}
|
|
}
|
|
|
|
COM_RELEASE (pversion_enum);
|
|
}
|
|
|
|
// Get the date of this file
|
|
/*if (::IDispatch_Get_Property (pcheckout, 0x00000004, &result)) {
|
|
COleDateTime date_obj (result.dateVal);
|
|
SYSTEMTIME system_time;
|
|
date_obj.GetAsSystemTime (system_time);
|
|
|
|
LPTSTR username = ::Sys_String_To_ANSI (result.bstrVal);
|
|
|
|
// Copy the username back to the buffer the caller supplied
|
|
::lstrcpyn (checked_out_username, username, buffer_size);
|
|
checked_out_username[buffer_size-1] = 0;
|
|
|
|
// Free the temporary buffer we used to hold the username
|
|
delete [] username;
|
|
username = NULL;
|
|
}*/
|
|
|
|
COM_RELEASE (penum_variant);
|
|
}
|
|
|
|
// Release our hold on the interface
|
|
COM_RELEASE (pversions);
|
|
}
|
|
}
|
|
|
|
// Return the current file status
|
|
return true;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_File_Status
|
|
//
|
|
VSSFileStatus
|
|
VSSClass::Get_File_Status
|
|
(
|
|
LPCTSTR local_filename,
|
|
LPTSTR checked_out_username,
|
|
DWORD buffer_size,
|
|
IVSSItem * item_to_use
|
|
)
|
|
{
|
|
// Assume not checked out
|
|
VSSFileStatus status = VSSFILE_NOTCHECKEDOUT;
|
|
|
|
// Get a pointer to this 'item' inside the VSS database.
|
|
IVSSItem *pitem = item_to_use;
|
|
if (pitem == NULL) {
|
|
pitem = Get_VSS_Item_From_Local_Path (local_filename);
|
|
}
|
|
|
|
// Did we succesfully get the VSS item?
|
|
ASSERT (pitem != NULL);
|
|
if (pitem != NULL) {
|
|
|
|
// Get the current check-out status for this item
|
|
VARIANT result = { 0 };
|
|
::IDispatch_Get_Property (pitem, 0x0000000e, &result);
|
|
|
|
// Pass the result back to the caller
|
|
status = (VSSFileStatus)result.lVal;
|
|
|
|
// Should we lookup the name of user who has this file checked out?
|
|
if ((status != VSSFILE_NOTCHECKEDOUT) &&
|
|
(checked_out_username != NULL)) {
|
|
|
|
// Get a pointer to the 'checkouts' interface for this item
|
|
bool success = ::IDispatch_Get_Property (pitem, 0x0000000f, &result);
|
|
IVSSCheckouts *pcheckouts = (IVSSCheckouts *)result.ppdispVal;
|
|
|
|
if (success && (pcheckouts != NULL)) {
|
|
|
|
// Get the count of 'checkouts' on this file (should be 1 for our purposes)
|
|
if (::IDispatch_Get_Property (pcheckouts, 0x00000001, &result)) {
|
|
int count = result.lVal;
|
|
if (count > 0) {
|
|
|
|
VARIANT var_test = { 0 };
|
|
var_test.vt = VT_I4;
|
|
var_test.lVal = 1;
|
|
|
|
VARIANT var_arg = { 0 };
|
|
var_arg.vt = VT_VARIANT | VT_BYREF;
|
|
var_arg.pvarVal = &var_test;
|
|
|
|
// Attempt to lookup an interface that represents the first 'checkout'.
|
|
// Remember, VSS supports multiple checkouts per file.
|
|
if (::IDispatch_Get_Property (pcheckouts, 00000000, var_arg, &result)) {
|
|
IVSSCheckout *pcheckout = (IVSSCheckout *)result.ppdispVal;
|
|
|
|
// Get the username of this 'checkout'
|
|
if (::IDispatch_Get_Property (pcheckout, 0x00000001, &result)) {
|
|
LPTSTR username = ::Sys_String_To_ANSI (result.bstrVal);
|
|
|
|
// Copy the username back to the buffer the caller supplied
|
|
::lstrcpyn (checked_out_username, username, buffer_size);
|
|
checked_out_username[buffer_size-1] = 0;
|
|
|
|
// Free the temporary buffer we used to hold the username
|
|
delete [] username;
|
|
username = NULL;
|
|
}
|
|
|
|
// Release our hold on the checkout interface
|
|
COM_RELEASE (pcheckout);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Release our hold on the interface
|
|
COM_RELEASE (pcheckouts);
|
|
}
|
|
}
|
|
|
|
// Release our hold on the item
|
|
if (item_to_use == NULL) {
|
|
COM_RELEASE (pitem);
|
|
}
|
|
}
|
|
|
|
// Return the current file status
|
|
return status;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Error_Description
|
|
//
|
|
LPCTSTR
|
|
VSSClass::Get_Error_Description (HRESULT hresult)
|
|
{
|
|
LPCTSTR description = NULL;
|
|
|
|
// Loop through all the VSS specific errors that we know about
|
|
int error_count = sizeof (_ErrorArray) / sizeof (VSS_ERROR);
|
|
for (int error = 0;
|
|
(error < error_count) && (description == NULL);
|
|
error ++) {
|
|
|
|
// Is this the error we are looking for?
|
|
if (_ErrorArray[error].hresult == hresult) {
|
|
description = _ErrorArray[error].description;
|
|
}
|
|
}
|
|
|
|
// Return a string containing the error description.
|
|
return description;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Retry_Check_Out
|
|
//
|
|
bool
|
|
VSSClass::Retry_Check_Out
|
|
(
|
|
LPCTSTR local_filename,
|
|
int iattempts,
|
|
int idelay
|
|
)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
// Try for up to 'iattempts' times to check-out the file
|
|
for (int iattempt = 0; (iattempt < iattempts) && !retval; iattempt ++) {
|
|
|
|
// Attempt to checkout the file, if unsucccessful, then wait for a second
|
|
retval = Check_Out (local_filename);
|
|
if (retval == false) {
|
|
::Sleep (idelay);
|
|
}
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Retry_Check_In
|
|
//
|
|
bool
|
|
VSSClass::Retry_Check_In
|
|
(
|
|
LPCTSTR local_filename,
|
|
int iattempts,
|
|
int idelay
|
|
)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
// Try for up to 'iattempts' times to check-in the file
|
|
for (int iattempt = 0; (iattempt < iattempts) && !retval; iattempt ++) {
|
|
|
|
// Attempt to checkin the file, if unsucccessful, then wait for a second
|
|
retval = Check_In (local_filename);
|
|
if (retval == false) {
|
|
::Sleep (idelay);
|
|
}
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Recursive
|
|
//
|
|
void
|
|
VSSClass::Get_Recursive
|
|
(
|
|
LPCTSTR local_path,
|
|
IVSSItem *pparent
|
|
)
|
|
{
|
|
// Get a pointer to the 'IVSSItems' interface for this item
|
|
VARIANT result = { 0 };
|
|
//bool success = ::IDispatch_Get_Property (pparent, 0x00000009, &result);
|
|
|
|
IVSSItems *pitems = NULL;
|
|
pparent->get_Items (0, &pitems);
|
|
//IVSSItems *pitems = (IVSSItems *)result.ppdispVal;
|
|
|
|
if (pitems != NULL) {
|
|
|
|
// Get the sub-item count
|
|
if (::IDispatch_Get_Property (pitems, 0x00000001, &result)) {
|
|
int count = result.lVal;
|
|
for (int index = 0; index < count; index ++) {
|
|
|
|
VARIANT var_index = { 0 };
|
|
var_index.vt = VT_I4;
|
|
var_index.lVal = index + 1;
|
|
|
|
VARIANT var_arg = { 0 };
|
|
var_arg.vt = VT_VARIANT | VT_BYREF;
|
|
var_arg.pvarVal = &var_index;
|
|
|
|
// Get the subitem at this index
|
|
if (::IDispatch_Get_Property (pitems, 0x00000000, var_arg, &result)) {
|
|
IVSSItem *psub_item = (IVSSItem *)result.ppdispVal;
|
|
if (psub_item != NULL) {
|
|
|
|
// Get the sub-item's name
|
|
TCHAR sub_item_name[MAX_PATH] = { 0 };
|
|
if (::IDispatch_Get_Property (psub_item, 0x00000006, &result)) {
|
|
char *ansi_name = ::Sys_String_To_ANSI (result.bstrVal);
|
|
::lstrcpy (sub_item_name, ansi_name);
|
|
SAFE_DELETE (ansi_name);
|
|
}
|
|
|
|
// Build a filename from the path and the subitem name
|
|
TCHAR sub_item_path[MAX_PATH];
|
|
::lstrcpy (sub_item_path, local_path);
|
|
if (sub_item_path[::lstrlen (sub_item_path)-1] != '\\') {
|
|
::lstrcat (sub_item_path, "\\");
|
|
}
|
|
::lstrcat (sub_item_path, sub_item_name);
|
|
|
|
// Get the sub-item's type
|
|
VSSItemType sub_item_type = VSSITEM_PROJECT;
|
|
if (::IDispatch_Get_Property (psub_item, 0x00000004, &result)) {
|
|
sub_item_type = (VSSItemType)result.lVal;
|
|
}
|
|
|
|
// Recursively 'get' items for this subitem
|
|
if (sub_item_type == VSSITEM_PROJECT) {
|
|
Get_Recursive (sub_item_path, psub_item);
|
|
} else {
|
|
Get (sub_item_path, psub_item);
|
|
}
|
|
|
|
// Release our hold on this subitem's interface
|
|
COM_RELEASE (psub_item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Release our hold on the interface
|
|
COM_RELEASE (pitems);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Check_Out_Ex
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
bool
|
|
VSSClass::Check_Out_Ex (LPCTSTR local_filename, HWND parent_wnd)
|
|
{
|
|
bool retval = false;
|
|
|
|
//
|
|
// Determine the checkout status of the file
|
|
//
|
|
CString user_name;
|
|
VSSFileStatus status = Get_File_Status (local_filename, user_name.GetBufferSetLength (64), 64);
|
|
if (status == VSSFILE_NOTCHECKEDOUT) {
|
|
|
|
//
|
|
// Check out the file
|
|
//
|
|
retval = Retry_Check_Out (local_filename, 10, 250);
|
|
if (retval == false) {
|
|
CString message;
|
|
message.Format ("Unable to check out %s.", local_filename);
|
|
::MessageBox (parent_wnd, message, "VSS Error", MB_ICONERROR | MB_OK);
|
|
}
|
|
|
|
} else if (status == VSSFILE_CHECKEDOUT) {
|
|
|
|
//
|
|
// Let the user know who has the file checked out.
|
|
//
|
|
CString message;
|
|
message.Format ("User %s already has this file checked out.", user_name);
|
|
::MessageBox (parent_wnd, message, "Checkout Error", MB_ICONEXCLAMATION | MB_OK);
|
|
} else if (status == VSSFILE_CHECKEDOUT_ME) {
|
|
retval = true;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Check_In_Ex
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
bool
|
|
VSSClass::Check_In_Ex (LPCTSTR local_filename, HWND parent_wnd)
|
|
{
|
|
bool retval = false;
|
|
|
|
//
|
|
// Make sure the file is checked out to the current user
|
|
//
|
|
if (Get_File_Status (local_filename) == VSSFILE_CHECKEDOUT_ME) {
|
|
|
|
//
|
|
// Check in the file
|
|
//
|
|
retval = Retry_Check_In (local_filename, 10, 250);
|
|
if (retval == false) {
|
|
CString message;
|
|
message.Format ("Unable to check in file: %s.", local_filename);
|
|
::MessageBox (parent_wnd, message, "VSS Error", MB_ICONERROR | MB_OK);
|
|
}
|
|
|
|
} else if (Does_File_Exist (local_filename) == false) {
|
|
|
|
//
|
|
// If the file did not exist, then add it to the database.
|
|
//
|
|
retval = Add_File (local_filename);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_File_Status
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
AssetDatabaseClass::FILE_STATUS
|
|
VSSClass::Get_File_Status (LPCTSTR local_filename, StringClass *checked_out_user_name)
|
|
{
|
|
AssetDatabaseClass::FILE_STATUS retval = AssetDatabaseClass::UNKNOWN;
|
|
|
|
LPTSTR username = NULL;
|
|
DWORD buffer_size = 0;
|
|
|
|
if (checked_out_user_name != NULL) {
|
|
username = checked_out_user_name->Get_Buffer (64);
|
|
buffer_size = 64;
|
|
}
|
|
|
|
//
|
|
// Lookup the vss status of this file
|
|
//
|
|
VSSFileStatus vss_status = Get_File_Status (local_filename, username, buffer_size);
|
|
|
|
//
|
|
// Map the return value to a generic
|
|
//
|
|
if (vss_status == VSSFILE_CHECKEDOUT_ME) {
|
|
retval = AssetDatabaseClass::CHECKED_OUT_TO_ME;
|
|
} else if (vss_status == VSSFILE_NOTCHECKEDOUT) {
|
|
retval = AssetDatabaseClass::NOT_CHECKED_OUT;
|
|
} else if (vss_status == VSSFILE_CHECKEDOUT) {
|
|
retval = AssetDatabaseClass::CHECKED_OUT;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_File
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
FileClass *
|
|
VSSClass::Get_File (LPCTSTR local_filename)
|
|
{
|
|
//
|
|
// Do this to get around an oddity of the class when you pass in
|
|
// the filename to the constructor
|
|
//
|
|
RawFileClass *file_obj = new RawFileClass;
|
|
file_obj->Set_Name (local_filename);
|
|
return file_obj;
|
|
}
|
|
|