Pregunta

Antes de describir mi problema, aquí hay una descripción del programa (IHExplorer.exe) que estoy escribiendo:

Esta es una aplicación C++.

La aplicación IHExplorer debe parecerse lo más posible a una ventana del Explorador de Windows.Con una excepción, y es que al iniciar archivos desde esta ventana del Explorador, primero se los descifrará en la carpeta temporal del usuario, luego se iniciará la aplicación asociada con la extensión del archivo y se eliminará el archivo al cerrar.

El problema que tengo es con la eliminación automática cuando se cierra el archivo.Aquí hay un escenario:

  1. El usuario hace doble clic en un archivo .txt cifrado en IHExplorer.
  2. IHExplorer descifra el archivo .txt en la memoria, luego lo escribe en %TEMP% usando ::CreateFile que devuelve un HANDLE al archivo (IHExplorer debe mantener este identificador abierto al menos hasta que se ejecute el archivo .txt).

  3. IHExplorer Shell Ejecuta el archivo .txt (llamando a ::ShellExecute) desde su ubicación temporal.

  4. Ahora IHExplorer y el Bloc de notas tienen un identificador para abrir el archivo.
  5. El archivo debe eliminarse automáticamente cuando tanto IHExplorer como el Bloc de notas hayan cerrado su identificador del archivo, incluso si IHExplorer se cierra primero.

OK.Ese es un caso de usuario básico que describe lo que quiero que suceda.El problema que tengo es cuando i :: shelExeCute (), el bloc de notas dice: "El proceso no puede acceder al archivo porque está siendo utilizado por otro proceso". (que sería iHexplorer).Necesito solucionar este problema y abrir el bloc de notas incluso cuando todavía tengo el identificador abierto en IHExplorer.

Así es como se ve mi llamada a ::CreateFile:

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);

Observe que utilicé FILE_SHARE_DELETE para que otros procesos (como el Bloc de notas) puedan abrir el archivo con acceso de eliminación.

Observe que utilicé el archivo_attribute_temporario | FILE_FLAG_DELETE_ON_CLOSE Atributos para indicar que el archivo es temporal y debe eliminarse al cierre.

Observe también el parámetro &sa.Esta es la estructura SECURITY_ATTRIBUTES que estoy usando y creo (espero) que aquí es donde radica mi problema.Aquí está el código nuevamente, esta vez publicaré la función completa para que puedas ver cómo completo la estructura 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;
}

Creo que si determino el SECURITY_DESCRIPTOR correcto para pasar a ::CreateFile, puede funcionar como quiero.Por favor ayuda.

Por cierto, la función LaunchFile simplemente termina llamando a ::ShellExecute para iniciar el archivo.

¿Fue útil?

Solución

Después de volver a leer el documento msdn, me temo haber respondido mi propia pregunta.FILE_FLAG_DELETE_ON_CLOSE El archivo se eliminará inmediatamente después de cerrar todos sus identificadores, lo que incluye el identificador especificado y cualquier otro identificador abierto o duplicado.Si existen identificadores abiertos para un archivo, la llamada falla a menos que todos se hayan abierto con el modo compartido FILE_SHARE_DELETE.Las solicitudes de apertura posteriores del archivo fallan, a menos que se especifique el modo de compartir FILE_SHARE_DELETE.En mi caso, dudo que el Bloc de notas solicite el permiso FILE_SHARE_DELETE, por lo que no puede abrir el archivo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top