Redo how we extract files from a cabinet in order to dramatically
improve performance, especially if picking and choosing files out of the cabinet.
This commit is contained in:
parent
9adacf6a72
commit
b9c6b85779
209
dlls/msi/files.c
209
dlls/msi/files.c
|
@ -125,7 +125,6 @@ typedef struct
|
||||||
{
|
{
|
||||||
MSIPACKAGE* package;
|
MSIPACKAGE* package;
|
||||||
LPCSTR cab_path;
|
LPCSTR cab_path;
|
||||||
LPCSTR file_name;
|
|
||||||
} CabData;
|
} CabData;
|
||||||
|
|
||||||
static void * cabinet_alloc(ULONG cb)
|
static void * cabinet_alloc(ULONG cb)
|
||||||
|
@ -195,7 +194,6 @@ static long cabinet_seek(INT_PTR hf, long dist, int seektype)
|
||||||
|
|
||||||
static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
|
static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
|
||||||
{
|
{
|
||||||
/* FIXME: try to do more processing in this function */
|
|
||||||
switch (fdint)
|
switch (fdint)
|
||||||
{
|
{
|
||||||
case fdintCOPY_FILE:
|
case fdintCOPY_FILE:
|
||||||
|
@ -208,9 +206,29 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
|
||||||
LPWSTR trackpath;
|
LPWSTR trackpath;
|
||||||
LPWSTR tracknametmp;
|
LPWSTR tracknametmp;
|
||||||
static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
|
static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
|
||||||
|
LPWSTR given_file;
|
||||||
|
INT index;
|
||||||
|
|
||||||
if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1))
|
MSIRECORD * uirow;
|
||||||
|
LPWSTR uipath;
|
||||||
|
|
||||||
|
given_file = strdupAtoW(pfdin->psz1);
|
||||||
|
index = get_loaded_file(data->package, given_file);
|
||||||
|
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
ERR("Unknown File in Cabinent (%s)\n",debugstr_w(given_file));
|
||||||
|
HeapFree(GetProcessHeap(),0,given_file);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!((data->package->files[index].State == 1 ||
|
||||||
|
data->package->files[index].State == 2)))
|
||||||
|
{
|
||||||
|
TRACE("Skipping extraction of %s\n",debugstr_w(given_file));
|
||||||
|
HeapFree(GetProcessHeap(),0,given_file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
file = cabinet_alloc((len+1)*sizeof(char));
|
file = cabinet_alloc((len+1)*sizeof(char));
|
||||||
strcpy(file, data->cab_path);
|
strcpy(file, data->cab_path);
|
||||||
|
@ -233,6 +251,19 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
|
||||||
HeapFree(GetProcessHeap(),0,trackname);
|
HeapFree(GetProcessHeap(),0,trackname);
|
||||||
HeapFree(GetProcessHeap(),0,tracknametmp);
|
HeapFree(GetProcessHeap(),0,tracknametmp);
|
||||||
|
|
||||||
|
/* the UI chunk */
|
||||||
|
uirow=MSI_CreateRecord(9);
|
||||||
|
MSI_RecordSetStringW(uirow,1,data->package->files[index].File);
|
||||||
|
uipath = strdupW(data->package->files[index].TargetPath);
|
||||||
|
*(strrchrW(uipath,'\\')+1)=0;
|
||||||
|
MSI_RecordSetStringW(uirow,9,uipath);
|
||||||
|
MSI_RecordSetInteger(uirow,6,data->package->files[index].FileSize);
|
||||||
|
ui_actiondata(data->package,szInstallFiles,uirow);
|
||||||
|
msiobj_release( &uirow->hdr );
|
||||||
|
HeapFree(GetProcessHeap(),0,uipath);
|
||||||
|
|
||||||
|
ui_progress(data->package,2,data->package->files[index].FileSize,0,0);
|
||||||
|
|
||||||
return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
|
return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
|
||||||
}
|
}
|
||||||
case fdintCLOSE_FILE_INFO:
|
case fdintCLOSE_FILE_INFO:
|
||||||
|
@ -259,19 +290,17 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
|
||||||
*
|
*
|
||||||
* Extract files from a cab file.
|
* Extract files from a cab file.
|
||||||
*/
|
*/
|
||||||
static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
|
static BOOL extract_cabinet_file(MSIPACKAGE* package, LPCWSTR source,
|
||||||
const WCHAR* path, const WCHAR* file)
|
LPCWSTR path)
|
||||||
{
|
{
|
||||||
HFDI hfdi;
|
HFDI hfdi;
|
||||||
ERF erf;
|
ERF erf;
|
||||||
BOOL ret;
|
BOOL ret;
|
||||||
char *cabinet;
|
char *cabinet;
|
||||||
char *cab_path;
|
char *cab_path;
|
||||||
char *file_name;
|
|
||||||
CabData data;
|
CabData data;
|
||||||
|
|
||||||
TRACE("Extracting %s (%s) to %s\n",debugstr_w(source),
|
TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
|
||||||
debugstr_w(file), debugstr_w(path));
|
|
||||||
|
|
||||||
hfdi = FDICreate(cabinet_alloc,
|
hfdi = FDICreate(cabinet_alloc,
|
||||||
cabinet_free,
|
cabinet_free,
|
||||||
|
@ -302,11 +331,6 @@ static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
|
||||||
|
|
||||||
data.package = package;
|
data.package = package;
|
||||||
data.cab_path = cab_path;
|
data.cab_path = cab_path;
|
||||||
if (file)
|
|
||||||
file_name = strdupWtoA(file);
|
|
||||||
else
|
|
||||||
file_name = NULL;
|
|
||||||
data.file_name = file_name;
|
|
||||||
|
|
||||||
ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
|
ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
|
||||||
|
|
||||||
|
@ -317,13 +341,26 @@ static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, cabinet);
|
HeapFree(GetProcessHeap(), 0, cabinet);
|
||||||
HeapFree(GetProcessHeap(), 0, cab_path);
|
HeapFree(GetProcessHeap(), 0, cab_path);
|
||||||
HeapFree(GetProcessHeap(), 0, file_name);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
|
static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, MSICOMPONENT*
|
||||||
MSIFILE* file)
|
comp, LPCWSTR path)
|
||||||
|
{
|
||||||
|
if (file->Attributes & msidbFileAttributesNoncompressed)
|
||||||
|
{
|
||||||
|
LPWSTR p;
|
||||||
|
p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
|
||||||
|
file->SourcePath = build_directory_name(2, p, file->ShortName);
|
||||||
|
HeapFree(GetProcessHeap(),0,p);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
file->SourcePath = build_directory_name(2, path, file->File);
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex,
|
||||||
|
MSICOMPONENT* comp)
|
||||||
{
|
{
|
||||||
UINT rc = ERROR_SUCCESS;
|
UINT rc = ERROR_SUCCESS;
|
||||||
MSIRECORD * row = 0;
|
MSIRECORD * row = 0;
|
||||||
|
@ -338,27 +375,46 @@ static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
|
||||||
DWORD sz;
|
DWORD sz;
|
||||||
INT seq;
|
INT seq;
|
||||||
static UINT last_sequence = 0;
|
static UINT last_sequence = 0;
|
||||||
|
static LPWSTR last_path = NULL;
|
||||||
|
MSIFILE* file = NULL;
|
||||||
|
|
||||||
if (file->Attributes & msidbFileAttributesNoncompressed)
|
/* cleanup signal */
|
||||||
|
if (!package)
|
||||||
{
|
{
|
||||||
TRACE("Uncompressed File, no media to ready.\n");
|
HeapFree(GetProcessHeap(),0,last_path);
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file = &package->files[fileindex];
|
||||||
|
|
||||||
if (file->Sequence <= last_sequence)
|
if (file->Sequence <= last_sequence)
|
||||||
{
|
{
|
||||||
|
set_file_source(package,file,comp,last_path);
|
||||||
TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
|
TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
|
||||||
/*extract_a_cabinet_file(package, source,path,file->File); */
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence);
|
row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence);
|
||||||
if (!row)
|
if (!row)
|
||||||
|
{
|
||||||
|
TRACE("Unable to query row\n");
|
||||||
return ERROR_FUNCTION_FAILED;
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
seq = MSI_RecordGetInteger(row,2);
|
seq = MSI_RecordGetInteger(row,2);
|
||||||
last_sequence = seq;
|
last_sequence = seq;
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(),0,last_path);
|
||||||
|
last_path = NULL;
|
||||||
|
|
||||||
|
if (file->Attributes & msidbFileAttributesNoncompressed)
|
||||||
|
{
|
||||||
|
last_path = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
|
||||||
|
set_file_source(package,file,comp,last_path);
|
||||||
|
msiobj_release(&row->hdr);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
cab = MSI_RecordGetString(row,4);
|
cab = MSI_RecordGetString(row,4);
|
||||||
if (cab)
|
if (cab)
|
||||||
{
|
{
|
||||||
|
@ -367,12 +423,13 @@ static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
|
||||||
if (cab[0]=='#')
|
if (cab[0]=='#')
|
||||||
{
|
{
|
||||||
writeout_cabinet_stream(package,&cab[1],source);
|
writeout_cabinet_stream(package,&cab[1],source);
|
||||||
strcpyW(path,source);
|
last_path = strdupW(source);
|
||||||
*(strrchrW(path,'\\')+1)=0;
|
*(strrchrW(last_path,'\\')+1)=0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sz = MAX_PATH;
|
sz = MAX_PATH;
|
||||||
|
last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));
|
||||||
if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
|
if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
|
||||||
{
|
{
|
||||||
ERR("No Source dir defined \n");
|
ERR("No Source dir defined \n");
|
||||||
|
@ -380,24 +437,29 @@ static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strcpyW(path,source);
|
strcpyW(last_path,source);
|
||||||
strcatW(source,cab);
|
strcatW(source,cab);
|
||||||
/* extract the cab file into a folder in the temp folder */
|
/* extract the cab file into a folder in the temp folder */
|
||||||
sz = MAX_PATH;
|
sz = MAX_PATH;
|
||||||
if (MSI_GetPropertyW(package, cszTempFolder,path, &sz)
|
if (MSI_GetPropertyW(package, cszTempFolder,last_path, &sz)
|
||||||
!= ERROR_SUCCESS)
|
!= ERROR_SUCCESS)
|
||||||
GetTempPathW(MAX_PATH,path);
|
GetTempPathW(MAX_PATH,last_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc = !extract_a_cabinet_file(package, source,path,NULL);
|
rc = !extract_cabinet_file(package, source, last_path);
|
||||||
|
/* reaquire file ptr */
|
||||||
|
file = &package->files[fileindex];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sz = MAX_PATH;
|
sz = MAX_PATH;
|
||||||
|
last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));
|
||||||
MSI_GetPropertyW(package,cszSourceDir,source,&sz);
|
MSI_GetPropertyW(package,cszSourceDir,source,&sz);
|
||||||
strcpyW(path,source);
|
strcpyW(last_path,source);
|
||||||
}
|
}
|
||||||
|
set_file_source(package, file, comp, last_path);
|
||||||
msiobj_release(&row->hdr);
|
msiobj_release(&row->hdr);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,12 +488,17 @@ inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
|
||||||
return ERROR_FUNCTION_FAILED;
|
return ERROR_FUNCTION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In order to make this work more effeciencly I am going to do this in 2
|
||||||
|
* passes.
|
||||||
|
* Pass 1) Correct all the TargetPaths and determin what files are to be
|
||||||
|
* installed.
|
||||||
|
* Pass 2) Extract Cabinents and copy files.
|
||||||
|
*/
|
||||||
UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
||||||
{
|
{
|
||||||
UINT rc = ERROR_SUCCESS;
|
UINT rc = ERROR_SUCCESS;
|
||||||
DWORD index;
|
DWORD index;
|
||||||
MSIRECORD * uirow;
|
|
||||||
WCHAR uipath[MAX_PATH];
|
|
||||||
|
|
||||||
if (!package)
|
if (!package)
|
||||||
return ERROR_INVALID_HANDLE;
|
return ERROR_INVALID_HANDLE;
|
||||||
|
@ -439,17 +506,17 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
||||||
/* increment progress bar each time action data is sent */
|
/* increment progress bar each time action data is sent */
|
||||||
ui_progress(package,1,1,0,0);
|
ui_progress(package,1,1,0,0);
|
||||||
|
|
||||||
|
/* Pass 1 */
|
||||||
for (index = 0; index < package->loaded_files; index++)
|
for (index = 0; index < package->loaded_files; index++)
|
||||||
{
|
{
|
||||||
WCHAR path_to_source[MAX_PATH];
|
|
||||||
MSIFILE *file;
|
MSIFILE *file;
|
||||||
|
MSICOMPONENT* comp = NULL;
|
||||||
|
|
||||||
file = &package->files[index];
|
file = &package->files[index];
|
||||||
|
|
||||||
if (file->Temporary)
|
if (file->Temporary)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex,
|
if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex,
|
||||||
INSTALLSTATE_LOCAL))
|
INSTALLSTATE_LOCAL))
|
||||||
{
|
{
|
||||||
|
@ -457,28 +524,15 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
||||||
TRACE("File %s is not scheduled for install\n",
|
TRACE("File %s is not scheduled for install\n",
|
||||||
debugstr_w(file->File));
|
debugstr_w(file->File));
|
||||||
|
|
||||||
|
file->State = 5;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((file->State == 1) || (file->State == 2))
|
if ((file->State == 1) || (file->State == 2))
|
||||||
{
|
{
|
||||||
LPWSTR p;
|
LPWSTR p = NULL;
|
||||||
MSICOMPONENT* comp = NULL;
|
|
||||||
|
|
||||||
TRACE("Installing %s\n",debugstr_w(file->File));
|
TRACE("Pass 1: %s\n",debugstr_w(file->File));
|
||||||
rc = ready_media_for_file(package, path_to_source, file);
|
|
||||||
/*
|
|
||||||
* WARNING!
|
|
||||||
* our file table could change here because a new temp file
|
|
||||||
* may have been created
|
|
||||||
*/
|
|
||||||
file = &package->files[index];
|
|
||||||
if (rc != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
ERR("Unable to ready media\n");
|
|
||||||
rc = ERROR_FUNCTION_FAILED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
create_component_directory( package, file->ComponentIndex);
|
create_component_directory( package, file->ComponentIndex);
|
||||||
|
|
||||||
|
@ -486,39 +540,56 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
||||||
|
|
||||||
if (file->ComponentIndex >= 0)
|
if (file->ComponentIndex >= 0)
|
||||||
comp = &package->components[file->ComponentIndex];
|
comp = &package->components[file->ComponentIndex];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERR("No Component for file\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
|
p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
|
||||||
HeapFree(GetProcessHeap(),0,file->TargetPath);
|
HeapFree(GetProcessHeap(),0,file->TargetPath);
|
||||||
|
|
||||||
file->TargetPath = build_directory_name(2, p, file->FileName);
|
file->TargetPath = build_directory_name(2, p, file->FileName);
|
||||||
HeapFree(GetProcessHeap(),0,p);
|
HeapFree(GetProcessHeap(),0,p);
|
||||||
|
|
||||||
if (file->Attributes & msidbFileAttributesNoncompressed)
|
|
||||||
{
|
|
||||||
p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
|
|
||||||
file->SourcePath = build_directory_name(2, p, file->ShortName);
|
|
||||||
HeapFree(GetProcessHeap(),0,p);
|
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
file->SourcePath = build_directory_name(2, path_to_source,
|
|
||||||
file->File);
|
|
||||||
|
|
||||||
|
/* Pass 2 */
|
||||||
|
for (index = 0; index < package->loaded_files; index++)
|
||||||
|
{
|
||||||
|
MSIFILE *file;
|
||||||
|
MSICOMPONENT* comp = NULL;
|
||||||
|
|
||||||
|
file = &package->files[index];
|
||||||
|
|
||||||
|
if (file->Temporary)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((file->State == 1) || (file->State == 2))
|
||||||
|
{
|
||||||
|
TRACE("Pass 2: %s\n",debugstr_w(file->File));
|
||||||
|
|
||||||
|
if (file->ComponentIndex >= 0)
|
||||||
|
comp = &package->components[file->ComponentIndex];
|
||||||
|
|
||||||
|
rc = ready_media_for_file(package, index, comp);
|
||||||
|
if (rc != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
ERR("Unable to ready media\n");
|
||||||
|
rc = ERROR_FUNCTION_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WARNING!
|
||||||
|
* our file table could change here because a new temp file
|
||||||
|
* may have been created. So reaquire our ptr.
|
||||||
|
*/
|
||||||
|
file = &package->files[index];
|
||||||
|
|
||||||
TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
|
TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
|
||||||
debugstr_w(file->TargetPath));
|
debugstr_w(file->TargetPath));
|
||||||
|
|
||||||
/* the UI chunk */
|
|
||||||
uirow=MSI_CreateRecord(9);
|
|
||||||
MSI_RecordSetStringW(uirow,1,file->File);
|
|
||||||
strcpyW(uipath,file->TargetPath);
|
|
||||||
*(strrchrW(uipath,'\\')+1)=0;
|
|
||||||
MSI_RecordSetStringW(uirow,9,uipath);
|
|
||||||
MSI_RecordSetInteger(uirow,6,file->FileSize);
|
|
||||||
ui_actiondata(package,szInstallFiles,uirow);
|
|
||||||
msiobj_release( &uirow->hdr );
|
|
||||||
ui_progress(package,2,file->FileSize,0,0);
|
|
||||||
|
|
||||||
|
|
||||||
if (file->Attributes & msidbFileAttributesNoncompressed)
|
if (file->Attributes & msidbFileAttributesNoncompressed)
|
||||||
rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
|
rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
|
||||||
else
|
else
|
||||||
|
@ -559,6 +630,8 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* cleanup */
|
||||||
|
ready_media_for_file(NULL, 0, NULL);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -608,9 +681,7 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MSI_RecordIsNull(row,4))
|
if (MSI_RecordIsNull(row,4))
|
||||||
{
|
|
||||||
strcpyW(dest_name,strrchrW(file_source,'\\')+1);
|
strcpyW(dest_name,strrchrW(file_source,'\\')+1);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sz=0x100;
|
sz=0x100;
|
||||||
|
|
Loading…
Reference in New Issue