CreateFile con il flag FILE_FLAG_DELETE_ON_CLOSE
-
21-09-2019 - |
Domanda
Prima di descrivere il mio problema, qui è una descrizione del programma (IHExplorer.exe) sto scrivendo:
Si tratta di un'applicazione C ++.
L'applicazione IHExplorer è quello di guardare come molto simile a una finestra di Esplora risorse il più possibile. Con una sola eccezione, e cioè che il lancio di file all'interno di questa finestra di Explorer li decifrare prima nella cartella Temp dell'utente, quindi avviare l'applicazione associata con l'estensione del file e cancellare il file su una stretta.
Il problema che sto avendo è con l'auto eliminare quando il file viene chiuso. Ecco uno scenario:
- utente fa doppio clic un file .txt crittografato in IHExplorer.
-
IHExplorer decifra il file .txt nella memoria, quindi lo scrive% TEMP% utilizzando :: CreateFile che restituisce un handle al file (IHExplorer deve mantenere questo handle aperto atleast fino a quando il file txt è coperture eseguite ).
-
IHExplorer shell esegue il file txt (chiamando :: ShellExecute) dalla sua posizione temporanea.
- Ora IHExplorer e notepad entrambi hanno un handle al file aperto.
- Il file deve essere cancellato automaticamente quando entrambi IHExplorer e un blocco note hanno entrambi chiuso la loro handle al file, anche se IHExplorer chiude prima.
OK. che è un caso d'uso basical che descrive quello che voglio che accada. Il problema che ho è quando :: ShellExecute (), blocco note dice: "Il processo non può accedere al file perché è utilizzato da un altro processo". (Che sarebbe IHExplorer). Ho bisogno di ottenere intorno a questo e hanno notepad aprirlo anche mentre ho ancora l'handle aperto in IHExplorer.
Ecco quello che la mia chiamata a :: CreateFile appare come:
DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
HANDLE hFile = ::CreateFile(strTempFile.c_str(), GENERIC_WRITE, dwShareMode, &sa, CREATE_NEW, dwFlagsAndAttributes, NULL);
Avviso ho usato FILE_SHARE_DELETE in modo che gli altri processi (ad esempio Blocco note) possono aprire il file con l'accesso di eliminazione.
Si noti che ho usato il FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE attribuisce al indicicate il file è temporanea e dovrebbe essere soppresso alla chiusura.
notare anche il parametro & sa. Questa è la struttura SECURITY_ATTRIBUTES che sto usando, e mi sento (speranza) questo è dove il mio problema. Ecco il codice di nuovo, questa volta mi post l'intera funzione in modo da poter vedere come compilo la struttura SECURITY_ATTRIBUTES:
int CIHExplorerDoc::OpenFile(std::string strFileName, bool bIsFullPath) {
std::string strFullFilePath;
if(bIsFullPath) {
strFullFilePath = strFileName;
strFileName = IHawk::RemovePath(strFileName);
}else {
strFullFilePath = m_strDirectory + strFileName;
}
if(!HasEncryptionFileExtension(strFullFilePath)) {
LaunchFile(strFullFilePath);
}else {
//it's an encrypted file, so open it and copy unencrypted file to temp.
IHawk::EncryptedFileHandle hEncryptedFile(strFullFilePath.c_str(), true, theApp.GetKeyServer());
if(hEncryptedFile.IsValid()) {
std::string strTempFile = g_strTempFolder + IHawk::ChangeFileExtension(strFileName, "");
//TODO: Determine what the LPSECURITY_ATTRIBUTES should be.
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
if(!InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION)) {
DWORD dwLastError = ::GetLastError();
LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to initialize security descriptor. GetLastError=" << dwLastError);
return dwLastError;
}
if(!SetSecurityDescriptorDacl(
&sd, // A pointer to the SECURITY_DESCRIPTOR structure to which the function adds the DACL
TRUE, // presence of a DACL in the security descriptor
NULL, // allows all access to the object
FALSE // DACL has been explicitly specified by a user
))
{
DWORD dwLastError = ::GetLastError();
LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to set security descriptor DACL. GetLastError=" << dwLastError);
return dwLastError;
}
if(!SetSecurityDescriptorGroup(
&sd, // A pointer to the SECURITY_DESCRIPTOR structure whose primary group is set by this function
NULL, // no primary group
FALSE // Indicates whether the primary group information was derived from a default mechanism
))
{
DWORD dwLastError = ::GetLastError();
LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to set security descriptor primary group. GetLastError=" << dwLastError);
return dwLastError;
}
if(!SetSecurityDescriptorOwner(
&sd, // A pointer to the SECURITY_DESCRIPTOR structure whose owner is set by this function.
NULL, // If this parameter is NULL, the function clears the security descriptor's owner information. This marks the security descriptor as having no owner.
FALSE // Indicates whether the owner information is derived from a default mechanism.
))
{
DWORD dwLastError = ::GetLastError();
LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to set security descriptor owner information. GetLastError=" << dwLastError);
return dwLastError;
}
if(!SetSecurityDescriptorSacl(
&sd, // A pointer to the SECURITY_DESCRIPTOR structure to which the function adds the SACL
FALSE, // the security descriptor does not contain a SACL
NULL, // security descriptor has a NULL SACL
FALSE // A pointer to a flag that is set to the value of the SE_SACL_DEFAULTED flag in the SECURITY_DESCRIPTOR_CONTROL structure if a SACL exists for the security descriptor
))
{
DWORD dwLastError = ::GetLastError();
LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to set security descriptor SACL. GetLastError=" << dwLastError);
return dwLastError;
}
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = TRUE;
DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
// DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
HANDLE hFile = ::CreateFile(strTempFile.c_str(), GENERIC_WRITE, dwShareMode, &sa, CREATE_NEW, dwFlagsAndAttributes, NULL);
//verify we created the file.
if(hFile == INVALID_HANDLE_VALUE) {
DWORD dwLastError = ::GetLastError();
return dwLastError;
}
//copy to temp
char buffer[64*1024];
size_t nBytesRead = hEncryptedFile.Read(buffer, sizeof(buffer));
while(nBytesRead) {
DWORD numBytesWritten;
if(!::WriteFile(hFile, buffer, nBytesRead, &numBytesWritten, (LPOVERLAPPED) NULL)) {
DWORD dwLastError = ::GetLastError();
LOG4CPLUS_ERROR(m_Logger, "Failed to write file to %TEMP% folder. GetLastError=" << dwLastError);
return dwLastError;
}
nBytesRead = hEncryptedFile.Read(buffer, sizeof(buffer));
}
hEncryptedFile.Close();
//execute the file from temp.
LaunchFile(strTempFile);
}
}
return 0;
}
Credo che se a determinare la corretta SECURITY_DESCRIPTOR di passare a :: CreateFile può funzionare come voglio io. Si prega di aiutare.
A proposito, la funzione LaunchFile appena finisce per chiamare :: ShellExecute per avviare il file.
Soluzione
Dopo aver riletto il documento MSDN, temo di aver risposto alla mia domanda. FILE_FLAG_DELETE_ON_CLOSE Il file deve essere eliminato subito dopo tutte le sue maniglie sono chiusi, che comprende l'handle specificato e tutti gli altri handle aperti o duplicati. Se ci sono handle aperti esistenti in un file, la chiamata non riesce a meno che non erano tutti aperti con la modalità FILE_SHARE_DELETE azione. Le successive richieste aperte per il file non riescono, se non è stata specificata la modalità FILE_SHARE_DELETE azione. Nel mio caso, dubito notepad sta richiedendo il permesso FILE_SHARE_DELETE, quindi non riesco ad aprire il file