SHFileOperation gives file system error 1026. Why?

This problem comes up periodically, and is usually due to the lack of double-nulling which SHFileOperation requires in its parameters (because they can be multi-file lists, delimited with single NULLs and terminated with a double NULL). Take the following code (this is all done in debug mode, by the way) :

void CTestbed2Dlg::test_shfo (CString& csFilesSrc, CString& csFilesDst)
{
   SHFILEOPSTRUCT shfos;
   char  szDebug [100];
   int   iSHerr;

   shfos.hwnd  = GetSafeHwnd();
   shfos.wFunc = FO_COPY;
   shfos.pFrom = csFilesSrc;
   shfos.pTo   = csFilesDst;

   shfos.fFlags= FOF_NOCONFIRMATION;
   shfos.lpszProgressTitle = "Testbed2";

   iSHerr = SHFileOperation (&shfos);
   if (iSHerr == 0)
      AfxMessageBox ("Worked fine");
   else
   {
      wsprintf (szDebug, "SHFO gave error %d", GetLastError());
      AfxMessageBox (szDebug);
   }
}

and call it like this :

CString csSrc;
CString csDst;

csSrc = "C:\\Scratch\\*.*";
csDst = "d:\\Scratch";
test_shfo (csSrc, csDst);

You'll get file system error 1026 every time. Modify the function code to use local arrays like this :

void CTestbed2Dlg::test_shfo (CString& csFilesSrc, CString& csFilesDst)
{
   SHFILEOPSTRUCT shfos;
   char  szDebug [100];
   int   iSHerr;
   char  szSrc [_MAX_PATH];
   char  szDst [_MAX_PATH];
   strcpy (szSrc, csFilesSrc);
   strcpy (szDst, csFilesDst);

   shfos.hwnd = GetSafeHwnd();
   shfos.wFunc = FO_COPY;
   shfos.pFrom = szSrc;
   shfos.pTo = szDst;

   shfos.fFlags= FOF_NOCONFIRMATION;
   shfos.lpszProgressTitle = "Testbed2";

   iSHerr = SHFileOperation (&shfos);
   if (iSHerr == 0)
      AfxMessageBox ("Worked fine");
   else
   {
      wsprintf (szDebug, "SHFO gave error %d", GetLastError());
      AfxMessageBox (szDebug);
   }
}

and call it exactly the same way, (note - still no explicit double-nulling), and it will work. More interestingly, if you leave the function code in its first form and call it like this.....

CString csSrc ('\0', _MAX_PATH);
CString csDst ('\0', _MAX_PATH);

csSrc = "C:\\Scratch\\*.*";
csDst = "d:\\Scratch";
test_shfo (csSrc, csDst);

...now the code will magically work. That odd CString constructor pre-fills the string, by the way. It looks like the problem lies with the lack of double nulling. So, to prove it, do this to the code which invokes SHFO

 
char  szSrc [_MAX_PATH];
char  szDst [_MAX_PATH];

// pack the arrays
memset (szSrc, 'A', sizeof(szSrc));
memset (szDst, 'A', sizeof(szDst));

// now copy in the strings (no double nulls)
strcpy (szSrc, csFilesSrc);
strcpy (szDst, csFilesDst);

shfos.hwnd = GetSafeHwnd();
shfos.wFunc = FO_COPY;
shfos.pFrom = szSrc;
shfos.pTo = szDst;

and the 1026 error comes back again.

Update, courtesy of Phil Wright:

This error value (1026) is also produced if an FO_DELETE operation is attempted for a file that doesn't exist, even if the string DOES end in a double-null. I have confirmed this. See this code:

SHFILEOPSTRUCT shfos = {0};
int    iSHerr;
char   szSrc [MAX_PATH];

ZeroMemory (szSrc, sizeof(szSrc));
strcpy (szSrc, "C:\\squiggly.zap");

shfos.hwnd = NULL;
shfos.wFunc = FO_DELETE;
shfos.pFrom = szSrc;
shfos.fFlags = FOF_NOERRORUI | FOF_NOCONFIRMATION | FOF_SILENT;

iSHerr = SHFileOperation (&shfos);

if (iSHerr == 0)
{
   AfxMessageBox ("squiggly.zap deleted ?! It doesn't exist!");
}
else
{
   wsprintf  (g_szDebug, "MF: SHFileOperation gave error %d", iSHerr);
   AfxMessageBox (g_szDebug);
} 

That code will also produce error 1026, despite being correct apart from one vital fact: C:/squiggly.zap doesn't exist (on my system anyway :-)). It seems that 1026 really means "something went wrong" :-(