Can't open file for reading file time information

Category: visual studio vclanguage

Question

Gurunama on Wed, 15 Apr 2020 12:57:06


I want to read the file time information of an exe file stored in the Download folder if possible. I can't, however, make the CreateFile function work. I have the following code:

PWSTR ppszPath; size_t IS = 0; char pszMore[1024]; LPCSTR pszPath; char *pszMore2 = &pszMore; DWORD Lasterror; SHGetKnownFolderPath(&FOLDERID_Downloads, 0, NULL, &ppszPath); wcstombs_s(&IS, pszMore, 1024, ppszPath, 1024); PathCombineA(pszMore, pszMore, "Testprog.exe"); pszPath = pszMore2; hFile4 = CreateFile(pszPath, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); Lasterror = GetLastError(); if (hFile4 != INVALID_HANDLE_VALUE) { timeresult = GetFileTime(hFile4, &lpCreate, &lpAccess, &lpWrite); //... }

The hFile variable gets the value 0xffffffff, and the Lasterror gets 3.

Thanks in advance.

Sincerely


Replies

RLWA32 on Wed, 15 Apr 2020 13:22:03


This code does not compile using VS2015.

Are you compiling as C or as C++?

And error code 3 is "The system cannot find the path specified."


Gurunama on Wed, 15 Apr 2020 14:24:20


Sorry, but I've tried so many different combinations to make this work that it seems that the one I gave was not 100% correct. So I give it again:

PWSTR ppszPath = NULL; size_t IS; char* pszMore = (char*)malloc(BUFFER_SIZE); LPCSTR pszPath; DWORD Lasterror;

SHGetKnownFolderPath(&FOLDERID_Downloads, 0, NULL, &ppszPath); wcstombs_s(&IS, pszMore, (size_t)BUFFER_SIZE, ppszPath, (size_t)BUFFER_SIZE);

PathCombineA(pszMore, pszMore, "Testprog.exe"); pszPath = pszMore; hFile4 = CreateFile(pszPath, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);

I am compiling in VS 2019 and programming in C. The path should be valid. I have among others tested it in the Windows command field. Lasterror now shows 3435973836.



RLWA32 on Wed, 15 Apr 2020 14:45:48


Sorry, but I've tried so many different combinations to make this work that it seems that the one I gave was not 100% correct. So I give it again:

PWSTR ppszPath = NULL; size_t IS; char* pszMore = (char*)malloc(BUFFER_SIZE); LPCSTR pszPath; DWORD Lasterror;

SHGetKnownFolderPath(&FOLDERID_Downloads, 0, NULL, &ppszPath); wcstombs_s(&IS, pszMore, (size_t)BUFFER_SIZE, ppszPath, (size_t)BUFFER_SIZE); PathCombineA(pszMore, pszMore, "DhruvaNada_01_setup.exe"); pszPath = pszMore; hFile4 = CreateFile(pszPath, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);

I am compiling in VS 2019, and I'm programming in C. The path should be valid. I have among others tested it in the Windows command field. Lasterror now shows 3435973836.

You should be testing the return values to make sure that functions you call have succeeded.  For example, check the HRESULT returned by SHGetKNownFolderPath.

The hex value of 3435973836 is 0xCCCCCC which is the value that a debug build places in an uninitialized variable.

Only call GetLastError if a Windows API call has failed and the documentation for the function indicates that extended error information is available.

	hFile4 = CreateFile(pszPath, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);

	if (hFile4 != INVALID_HANDLE_VALUE)
	{
		FILETIME lpCreate, lpAccess, lpWrite;
		if (!GetFileTime(hFile4, &lpCreate, &lpAccess, &lpWrite))
			Lasterror = GetLastError();
	}
	else
	{
		Lasterror = GetLastError();
	}

Castorix31 on Wed, 15 Apr 2020 15:13:00


You should use C++ syntax.

Otherwise this test in C works for me  for a random file "ChromeSetup.exe" I have in Download directory =>

LPWSTR pszDownloadPath = NULL;
WCHAR szFile[MAX_PATH] = L"ChromeSetup.exe";
SHGetKnownFolderPath(&FOLDERID_Downloads, 0, NULL, &pszDownloadPath);
WCHAR szDest[MAX_PATH] = L"";
PathCombineW(szDest, pszDownloadPath, szFile);
HANDLE hFile = CreateFileW(szDest, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
	FILETIME ftCreate, ftLastAccess, ftLastWrite;
	BOOL bOK = GetFileTime(hFile, &ftCreate, &ftLastAccess, &ftLastWrite);
	CloseHandle(hFile);

	FILETIME ftLocLastWrite;
	SYSTEMTIME st;
	FileTimeToLocalFileTime(&ftLastWrite, &ftLocLastWrite);
	FileTimeToSystemTime(&ftLocLastWrite, &st);

	TCHAR szText[255] = TEXT("");
	wsprintf(szText, TEXT("System (UTC) Last Write Date/Time: %.2d/%.2d/%d %d:%.2d:%.2d.%.4d"),
		st.wMonth, st.wDay,
		st.wYear, st.wHour,
		st.wMinute, st.wSecond,
		st.wMilliseconds);
	OutputDebugString(szText);
}

WayneAKing on Wed, 15 Apr 2020 15:23:56


I want to read the file time information of an exe file stored in the Download folder if possible. I can't, however, make the CreateFile function work. I have the following code:

PWSTR ppszPath; size_t IS = 0; char pszMore[1024]; LPCSTR pszPath; char *pszMore2 = &pszMore; DWORD Lasterror; SHGetKnownFolderPath(&FOLDERID_Downloads, 0, NULL, &ppszPath); wcstombs_s(&IS, pszMore, 1024, ppszPath, 1024); PathCombineA(pszMore, pszMore, "Testprog.exe"); pszPath = pszMore2; hFile4 = CreateFile(pszPath, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); Lasterror = GetLastError(); if (hFile4 != INVALID_HANDLE_VALUE) { timeresult = GetFileTime(hFile4, &lpCreate, &lpAccess, &lpWrite); //... }

The hFile variable gets the value 0xffffffff, and the Lasterror gets 3.


FWIW, I took your original code and added some code to it - much of it lifted
from the example here:

Retrieving the Last-Write Time
https://docs.microsoft.com/en-us/windows/win32/sysinfo/retrieving-the-last-write-time

I compiled it as C with Character Set = Multi-Byte.

I changed the file name searched for to one that happens to be in my download 
folder.

It found the file and displayed the correct time/date info for that file:

Last write time is: 11/08/2014  02:01

So as RLWA32 suggested, you need to check for success/failure of each step in
your code. Make NO assumptions. You can also step through the program to check 
the values in variables using the debugger.

Here is the *unpolished* code I ran. It is NOT robust and needs the checks
alluded to above. It was intended ONLY as a quick check for glaring errors
and/or omissions.

#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <stdio.h>
#include <strsafe.h>

int main()
{
    PWSTR ppszPath;
    size_t   IS = 0;
    char pszMore[1024];
    LPCSTR pszPath;
    char *pszMore2 = &pszMore;
    DWORD Lasterror;
    
    HANDLE hFile4;
    SYSTEMTIME stUTC, stLocal;
    DWORD dwRet;
    TCHAR lpszString[MAX_PATH];
    DWORD dwSize = MAX_PATH;
    FILETIME lpCreate, lpAccess, lpWrite;

    SHGetKnownFolderPath(&FOLDERID_Downloads, 0, NULL, &ppszPath);
    wcstombs_s(&IS, pszMore, 1024, ppszPath, 1024);
    //PathCombineA(pszMore, pszMore, "Testprog.exe");
    PathCombineA(pszMore, pszMore, "PowerPointViewer.exe");
    pszPath = pszMore2;

    hFile4 = CreateFile(pszPath, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
    
    if (hFile4 == INVALID_HANDLE_VALUE)
    {
        Lasterror = GetLastError();
        printf("LastError == %d\n", Lasterror);
        return INVALID_HANDLE_VALUE;
    }

    BOOL timeresult = GetFileTime(hFile4, &lpCreate, &lpAccess, &lpWrite);
    if (timeresult)
    {
        // Convert the last-write time to local time.
        FileTimeToSystemTime(&lpWrite, &stUTC);
        SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);

        // Build a string showing the date and time.
        dwRet = StringCchPrintf(lpszString, dwSize,
            TEXT("%02d/%02d/%d  %02d:%02d"),
            stLocal.wMonth, stLocal.wDay, stLocal.wYear,
            stLocal.wHour, stLocal.wMinute);
            printf(TEXT("Last write time is: %s\n"), lpszString);

    //...
    }
}

E&OE

- Wayne

Gurunama on Wed, 15 Apr 2020 19:49:10


Yes, it worked. Thank you very much. But I don't understand why this worked and not my own code, because your variable szDest and the one I used, pszPath, had the same content when I stepped through them in the debugging. Was it because you conequently used wide characters? Anyway, I'm very happy that I finally have a working code.

Sincerely

Gurunama on Wed, 15 Apr 2020 19:52:07


Actually, I don't see much difference between my own code and this, except that you have replaced (size_t)BUFFER_SIZE with 1024, and are using 

char *pszMore2 = &pszMore;

But this is something I also have tried previously.

Anyway, the code I got above worked, so I don't need this now. But thanks for your answering.

Sincerely


WayneAKing on Wed, 15 Apr 2020 23:16:16


Actually, I don't see much difference between my own code and this, except that you have replaced (size_t)BUFFER_SIZE with 1024, and are using 

char *pszMore2 = &pszMore;

But this is something I also have tried previously.


>Actually, I don't see much difference between my own code and this, 

Of course you don't. It *IS* your code from your *first* post as I stated
and as shown in the *quoted text* in my post.

>except that you have replaced (size_t)BUFFER_SIZE with 1024, 

I did NOT replace that. Look at your post that I quoted. The code you originally
posted. THAT is the code I *copied*.

>and are using 
>char *pszMore2 = &pszMore;

No, YOU were using that in your first code version. That's why it's in the code
I posted.

The whole point of my posting this example was precisely to show that YOUR code
as you originally posted it works just fine for me. I changed the file name,
and added some code to show an error message and to show the display of the
date/time from the file.

So the reason it wasn't working for you has never been satisfactorily explained.

- Wayne

RLWA32 on Thu, 16 Apr 2020 09:13:58


I agree with Wayne's comment.  The OP never addressed the issues pointed out in earlier posts.

It is also telling that after posting some revised code the complaint changed to "Lasterror now shows 3435973836".  It was explained that meant that the Lasterror variable was uninitialized.  When proper usage of GetLastError() was demonstrated the OP never followed up.

Oh well, we tried.

Gurunama on Thu, 16 Apr 2020 14:03:29


Thank you for your concern, and you are right. It's not understandable why my code didn't work. But it's not that important to me. I have spent a lot of time on this code, which is often the case when working with Winapi, as I find many of its features complicated and difficult to comprehend. I am, however, not a professional programmer, and therefore not very eager to spend more time on this. I just accept that there are many things about Winapi I don't quite understand. But as long as I have a working code I'm happy.  

Sincerely


RLWA32 on Thu, 16 Apr 2020 14:15:17


And what would you do if someone did not post code for you to copy?

Gurunama on Thu, 16 Apr 2020 20:56:53


Well first of all I don't think I would have managed without this forum and people like you. So I am very greateful for that. Sometimes I get stuck with an issue like this, and spend so many hours and days trying to figure it out, and if I didn't have this forum to turn to, I guess I just would have had to give up my programming projects. But usually someone like you is able to pinpoint what is wrong with my code, and then it's all settled. What is special this time is that no one is able to see any error, and you therefore suggest that I should continue doing research. The thing is that I have done research for almost a week now, stepping through the code with the debugger over again and over again, trying this, trying that. I have tried dozens of code examples from different web-sites, without succeeding with any of them. Whatever I did, I could not make the CreateFile function work, even though the variable it used had the correct content. The path was correct, as was shown in the Locals window in the debugger. I therefore don't see much point in spending more time on this, as I don't even know what more I could do to resolve this. But as I now have a code that do the job I want, I think it's best to just leave it at that.

Sincerely