6

私の問題を説明する前に、私が書いているプログラム (IHExplorer.exe) の説明を次に示します。

これは C++ アプリケーションです。

IHExplorer アプリケーションは、可能な限り Windows エクスプローラー ウィンドウに似た外観にする必要があります。1 つの例外を除き、このエクスプローラー ウィンドウ内からファイルを起動すると、最初にユーザーの一時フォルダーにファイルが復号化され、次にファイル拡張子に関連付けられたアプリが起動され、閉じるときにファイルが削除されます。

私が抱えている問題は、ファイルが閉じられたときの自動削除にあります。シナリオは次のとおりです。

  1. ユーザーは、IHExplorer で暗号化された .txt ファイルをダブルクリックします。
  2. IHExplorer は、メモリ内の .txt ファイルを復号化し、ファイルに HANDLE を返す ::CreateFile を使用して %TEMP% に書き込みます (IHExplorer は、.txt ファイルがシェルで実行されるまで、少なくともこのハンドルを開いたままにしておく必要があります)。

  3. IHExplorer Shell 一時的な場所から .txt ファイルを (::ShellExecute を呼び出して) 実行します。

  4. これで、IHExplorer とメモ帳の両方が、開いているファイルへのハンドルを持ちます。
  5. IHExplorer が最初に閉じた場合でも、IHExplorer とメモ帳の両方がファイルへのハンドルを閉じた場合、ファイルは自動削除される必要があります。

わかった。これは、私が実現したいことを説明する基本的なユーザー ケースです。私が抱えている問題は、::ShellExecute()、メモ帳に「別のプロセスで使用されているため、プロセスはファイルにアクセスできません」と表示されることです。(これは IHExplorer になります)。これを回避し、IHExplorer でハンドルを開いている間でもメモ帳を開く必要があります。

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

他のプロセス (メモ帳など) が削除アクセスでファイルを開くことができるように、FILE_SHARE_DELETE を使用したことに注意してください。

FILE_ATTRIBUTE_TEMPORARY | を使用したことに注意してください。FILE_FLAG_DELETE_ON_CLOSE 属性は、ファイルが一時的なものであり、閉じるときに削除する必要があることを示します。

&sa パラメータにも注意してください。これは私が使用している SECURITY_ATTRIBUTES 構造であり、私の問題はここにあると感じています (希望)。もう一度コードを示します。今回は関数全体を投稿して、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;
}

::CreateFile に渡す正しい SECURITY_DESCRIPTOR を決定すれば、希望どおりに機能する可能性があると思います。助けてください。

ところで、LaunchFile 関数は ::ShellExecute を呼び出してファイルを起動するだけです。

4

1 に答える 1

5

msdn docを読み直した後、私は自分の質問に答えたのではないかと心配しています。FILE_FLAG_DELETE_ON_CLOSEファイルは、指定されたハンドルと他の開いているまたは重複しているハンドルを含むすべてのハンドルが閉じられた直後に削除されます。ファイルに対して開いているハンドルが存在する場合、それらがすべてFILE_SHARE_DELETE共有モードで開かれていない限り、呼び出しは失敗します。FILE_SHARE_DELETE共有モードが指定されていない限り、後続のファイルのオープン要求は失敗します。私の場合、メモ帳がFILE_SHARE_DELETE権限を要求しているのではないので、ファイルを開くことができません。

于 2009-12-12T23:39:21.760 に答える