Solved

FindFirstFile and SHFileOperation

Posted on 1998-03-10
12
355 Views
Last Modified: 2013-11-20
I have a simple little code snippet that checks two files last write date/time to see whether they are different. If they are (or the Local doesn't exist), the code should then copy the Network copy over the local.

I am having two problems:
   1) The program is ALWAYS copying the file.
   2) The SHFileOperation sometimes comes back with it can't copy 'xxxx' file where 'xxxx' is just some stray garbage.

Here is the code snippet. Any suggestions?

      // create the paths to the database
      CString LocalDatabasePath,NetworkDatabasePath;
      if (CSPECFileName.IsEmpty()) NetworkDatabasePath = (LimitsDatabasePath + "\\Limits");
      else NetworkDatabasePath = (LimitsDatabasePath + "\\" + CSPECFileName);
      if (CSPECFileName.IsEmpty()) LocalDatabasePath = (LocalDataPath + "\\Limits");
      else LocalDatabasePath = (LocalDataPath + "\\" + CSPECFileName);

      // find file and get it's info (display error if we get invalid handles)
      WIN32_FIND_DATA NetFileInfo,LocFileInfo;
      if ((FindFirstFile((NetworkDatabasePath + ".dbf"),&NetFileInfo) == INVALID_HANDLE_VALUE) &&
            (FindFirstFile((LocalDatabasePath + ".dbf"),&LocFileInfo) == INVALID_HANDLE_VALUE))
            AfxMessageBox("Unable To Open Network Or Local Limits Files.\nNetwork Not Available Or Paths Incorrect.",
                  MB_OK | MB_ICONEXCLAMATION);
      // if we get good net handle and the file dates do not match, copy the net to the local
      else if (NetworkStatus)
            {
            if (NetFileInfo.ftLastWriteTime.dwLowDateTime != LocFileInfo.ftLastWriteTime.dwLowDateTime ||
                  NetFileInfo.ftLastWriteTime.dwHighDateTime != LocFileInfo.ftLastWriteTime.dwHighDateTime)
                  {
                  SHFILEOPSTRUCT sfo;
                  memset(&sfo,0,sizeof(sfo));
                  sfo.hwnd = ::GetTopWindow(NULL);
                  sfo.wFunc = FO_COPY;
                  sfo.pFrom = (NetworkDatabasePath + ".*\0\0");
                  sfo.pTo = (LocalDataPath + "\0\0");
                  sfo.fFlags = FOF_NOCONFIRMATION | FOF_SIMPLEPROGRESS;
                  sfo.lpszProgressTitle = ("Copying Modified Limits Database Files - Please Wait...");
                  ::SHFileOperation(&sfo);
                  }
            }
0
Comment
Question by:maknight
  • 5
  • 4
  • 3
12 Comments
 
LVL 4

Expert Comment

by:jtwine100697
ID: 1316867
  At first glance (I am tired), I do not know why the files is always being copied, but here is a guess for your "garbage filenames xxx" problem:

   When you use (CString + "constant") you are creating a temporary object.  Try storing composite filenames in a seperate CString object, AND putting NULLs into a CString tends to confuse the CString class.  Try using a regular char buffer.

-=- James.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 1316868
Two more things:

   o  You should be storing the HANDLE returned by FindFirstFile(...) to use with FindClose(...) later on.

   o  Check the ftLastWriteTime structures for both the remote and the local file:  If any of them they are zero (initalize them first with ZeroMemory(...) ), it means that the times could not be obtained.

-=- James.
0
 
LVL 23

Accepted Solution

by:
chensu earned 100 total points
ID: 1316869
There is a logical error in your code.

Look at
if ((FindFirstFile((NetworkDatabasePath + ".dbf"),&NetFileInfo) == INVALID_HANDLE_VALUE) && 
(FindFirstFile((LocalDatabasePath + ".dbf"),&LocFileInfo) == INVALID_HANDLE_VALUE))

Shouldn't you use || instead of &&?
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 1316870
  chensu...  Yes, there is a logical error in his error checking, and he would need still further (more robust) error checking to make it right, but that answers neither of his questions.

-=- James.
0
 
LVL 23

Expert Comment

by:chensu
ID: 1316871
jtwine,

I should have indicated that this error is likely to cause those two problems if only one of the FindFirstFile() functions returns INVALID_HANDLE_VALUE.
0
 

Author Comment

by:maknight
ID: 1316872
I am aware of the  of the lack of robust error-checking. That in itself should not cause the failure altogether of FindFirstFile to get the correct LastWriteTime. Added robustness is a secondary issue I'll resolve once the core code functions.

The && is correct since I am looking for the case when both files are not available- meaning the system cannot continue (handled elsewhere). The additional conditions in the else just make sure that at least the network copy is available for copying.

Let me look over your comments further and see if they point the way. I think I'm running into a NetWare issue (network file) since my local file is returning the LastWriteTime data properly.
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 

Author Comment

by:maknight
ID: 1316873
jtwine, Got your first comment taken care of. I knew that about CString. Guess I was tired yesterday as well...
0
 
LVL 23

Expert Comment

by:chensu
ID: 1316874
I don't think the usage of CString causes any problems. Yes, it is a temporary object. But it is alive as long as the execution does not go out of the scope. Using a regular char buffer is the same unless you use a global or static char buffer. The best way is to debug it carefully. Use TRACE and ASSERT liberally. They will help you avoid many problems.
0
 

Author Comment

by:maknight
ID: 1316875
I removed the TRACE and ASSERT statements from what I posted to make it cleaner for you folks here to read. They tend to clutter code sometimes <g>. Once I changed the two CStrings in the SHFILEOPSTRUCT to char SomeVar[Max_Path] that problem went away. The double NULL (\0\0) was seemingly driving it nuts. It was a soft drive to insanity b/c it would never really trap anything I could put in to try to trap it, but nonetheless it was going nuts.
0
 

Author Comment

by:maknight
ID: 1316876
Everything appears to be functioning well now. Thanks.
0
 
LVL 23

Expert Comment

by:chensu
ID: 1316877
You should have rejected my answer and given the points to jtwine since he did mention "putting NULLs into a CString tends to confuse the CString class". I didn't notice the double NULL problem.
0
 

Author Comment

by:maknight
ID: 1316878
Oops! Actually I didn't look to see who had it locked. Assumed the first to respond had locked it, but jtwine had only commented. Sorry, James. Thanks both.

About CString: It's nice, but it can also be a pain in the rear end sometimes since it seems several things can confuse it.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Folder Comparison 12 53
C++ BOOL WINAPI ReadFile fails on windows 10 when reading from USB cable 9 371
sum13 challenge 24 90
sum67 challenge 35 93
Introduction: Displaying information on the statusbar.   Continuing from the third article about sudoku.   Open the project in visual studio. Status bar – let’s display the timestamp there.  We need to get the timestamp from the document s…
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

943 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now