CreateFile avec le drapeau de FILE_FLAG_DELETE_ON_CLOSE
-
21-09-2019 - |
Question
Avant de décrire mon problème, voici une description du programme (IHExplorer.exe) J'cris:
Ceci est une application C ++.
L'application IHExplorer est de regarder autant comme une fenêtre Explorateur Windows que possible. À une exception près, et que le lancement de fichiers à partir de cette fenêtre Explorer les déchiffrer d'abord dans le dossier temporaire de l'utilisateur, puis lancer l'application associée à l'extension de fichier et supprimez le fichier à la fermeture.
Le problème que je vais avoir est la suppression automatique lorsque le fichier est fermé. Voici un scénario:
- double-clique l'utilisateur un fichier .txt crypté dans IHExplorer.
-
IHExplorer décrypte le fichier txt en mémoire, puis écrit à% TEMP% à l'aide :: CreateFile qui retourne une poignée dans le fichier (IHExplorer doit garder cette poignée ouverte atleast jusqu'à ce que le fichier txt est shell Exécuté ).
-
IHExplorer Shell Exécute le fichier txt (en appelant :: ShellExecute) à partir de son emplacement temporaire.
- Maintenant IHExplorer et bloc-notes ont tous deux une poignée dans le fichier ouvert.
- Le fichier doit être automatiquement supprimé lorsque les deux IHExplorer et notepad ont tous deux fermé leur poignée dans le fichier, même si IHExplorer ferme d'abord.
. qui est un cas basical utilisateur qui décrit ce que je veux arriver. Le problème que j'ai est quand je :: ShellExecute (), le bloc-notes dit: « Le processus ne peut pas accéder au fichier car il est utilisé par un autre processus. » (Ce qui serait IHExplorer). Je dois contourner cela et ont ouvert le bloc-notes encore pendant que j'ai encore la poignée ouverte IHExplorer.
Voici ce que mon appel à :: CreateFile ressemble à:
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);
Avis je FILE_SHARE_DELETE de sorte que d'autres processus (tels que le bloc-notes) peuvent ouvrir le fichier avec l'accès de suppression.
Notez que je le FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE attribue à indicicate le fichier est temporaire et devrait être supprimé à la fermeture.
Notez également le & sa paramètre. Ceci est la structure SECURITY_ATTRIBUTES que je me sers, et je me sens (espoir) c'est là est mon problème. Voici le code à nouveau, cette fois, je signalerai l'ensemble de la fonction afin que vous puissiez voir comment je remplir la structure 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;
}
Je pense que si je déterminer le SECURITY_DESCRIPTOR correct de passer à :: CreateFile il peut fonctionner comme je veux. S'il vous plaît aider.
BTW, la fonction LaunchFile se termine juste par appeler :: ShellExecute pour lancer le fichier.
La solution
Après re-lecture de la doc msdn, je crains d'avoir répondu à ma propre question. FILE_FLAG_DELETE_ON_CLOSE Le fichier doit être supprimé immédiatement après l'ensemble de ses poignées sont fermées, qui comprend la poignée spécifié et tous les autres descripteurs ouverts ou doubles. S'il y a des poignées ouvertes existantes dans un fichier, l'appel échoue à moins qu'ils étaient tous ouverts avec le mode de partage de FILE_SHARE_DELETE. demandes ouvertes suivantes pour le fichier échouent, à moins que le mode de partage de FILE_SHARE_DELETE est spécifiée. Dans mon cas, je doute notepad demande la permission de FILE_SHARE_DELETE, donc il ne peut pas ouvrir le fichier