Mahadeva
Mahadeva

Reputation: 1637

SHFileOperation cannot remove folder

I am writing a C++ Custom action for WiX that will be called during installation to remove any leftovers installed by the installer. Consider the following code:

UINT __stdcall DeleteResidue(MSIHANDLE hInstall)
{
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;
    LPWSTR lpFolderPath = NULL;
    std::wstring temp;
    SHFILEOPSTRUCT shFile;

    hr = WcaInitialize(hInstall, "DeleteResidue");
    ExitOnFailure(hr, "Failed to initialize");

    hr = WcaGetProperty(L"LPCOMMAPPDATAFOLDER",&lpFolderPath);
    ExitOnFailure(hr, "Failure in Finding Common App Data Folder");

    temp = std::wstring(lpFolderPath);
    temp+=L"\0\0";

    //Stop the LPA and LPA Monitor Service. Then delete the residue.
    WcaLog(LOGMSG_STANDARD, "Doing Delete Residue");

    ZeroMemory(&shFile, sizeof(shFile));
    shFile.hwnd = NULL;
    shFile.wFunc = FO_DELETE;
    shFile.pFrom = temp.c_str();
    shFile.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_NOERRORUI;
    BOOL res = DirectoryExists(lpFolderPath);
    if(res)
    {
        WcaLog(LOGMSG_STANDARD, "The directory exist");
        int result = SHFileOperation(&shFile);
        if(!result)
            WcaLog(LOGMSG_STANDARD, "The directory should have deleted by now");
        else
            WcaLog(LOGMSG_STANDARD, "The directory could not be deleted.Error code %d", result);
    }       
    else
    {
        WcaLog(LOGMSG_STANDARD, "It Seems the Installed Folder is No more there");
    }



LExit:
    er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
    return WcaFinalize(er);
}

In above code, we get C:\ProgramData inLPCOMMAPPDATAFOLDER. The doc states that pFrom should be double null terminated. However the return value of the code is 0x2 i.e. ERROR_FILE_NOT_FOUND. What is wrong in the code above?

Upvotes: 2

Views: 1000

Answers (1)

Mike Vine
Mike Vine

Reputation: 9837

You are not double nul terminating the pFrom.

You have a standard string (which includes the null terminator when you call .c_str() on it).

temp = std::wstring(lpFolderPath);

You then concatenate an empty string onto it:

temp+=L"\0\0";

This leaves the original string unchanged. This is because the std::string::operator+(const wchar_t*) takes a null terminated string. The fact that you have 2 nulls is immaterial it only reads up to the first null. It doesn't even add that null as what you've effectively given it is an empty string and the result of concatenating an empty string to something else is a no-op.

There's a few ways to solve this, but probably easiest is to change

temp+=L"\0\0";

to

temp.push_back(L'\0');

which explicitly adds another nul to the string so when you eventaully call temp.c_str() you'll get back the double nul-terminated string you need.

Upvotes: 2

Related Questions