MM4100 MM4100 - 1 month ago 6
C++ Question

c++ My method to get a files created date on windows os is crashing my console application

When I call the

Created
method it crashes my console application. If I have it commented it out my program runs fine. I am trying to obtain the created date for a file on a shared network drive (Windows OS) and I cannot figure out what the error is. I just want to be able to obtain the timestamp for when a file was created. If I can fix this method to do that it's great. If not, any replacement method that will produce the timestamp of when that file was created is just as acceptable. Any help or direction is greatly appreciated.

const wchar_t* created;

//created = Created(vs[i].c_str());

vs[i].c_str() represents this string //S001E002/Some Folder/some_subfolder/file.tif

#pragma comment(lib, "th32.lib")
#define VC_EXTRALEAN
#include "stdafx.h"
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <cstring>
#include <io.h>
//#include <dirent.h>
#include <stdio.h>
#include <shlwapi.h>
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <strsafe.h>
using namespace std;

//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
std::string GetLastErrorAsString()
{
//Get the error message, if any.
DWORD errorMessageID = ::GetLastError();
if(errorMessageID == 0)
return std::string(); //No error message has been recorded

LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);

std::string message(messageBuffer, size);

//Free the buffer.
LocalFree(messageBuffer);

return message.c_str();
}

__int64 FileSize(const wchar_t* name) //, bool _true
{
WIN32_FILE_ATTRIBUTE_DATA fad;
std::wstring temp;
wchar_t* created;
wchar_t* error;

if (!GetFileAttributesEx(name, GetFileExInfoStandard, &fad))
{
error = L"Error";
return -1; // error condition, could call GetLastError to find out more
}

LARGE_INTEGER size;
size.HighPart = fad.nFileSizeHigh;
size.LowPart = fad.nFileSizeLow;
//return (wchar_t*) size.QuadPart;
return size.QuadPart;
}

const wchar_t* Created(const wchar_t* name) //, bool _true
{
WIN32_FILE_ATTRIBUTE_DATA fad;
//std::wstring temp;
std::wstring created;
SYSTEMTIME st;

if (!GetFileAttributesEx(name, GetFileExInfoStandard, &fad))
{
std::wstring error(L"Error");
return error.c_str(); // error condition, could call GetLastError to find out more
}

if (!FileTimeToSystemTime(&fad.ftCreationTime, &st))
{
std::wstring error(L"Error getting created Time");
return error.c_str(); // error condition, could call GetLastError to find out more
}
std::wstring month((wchar_t*)st.wMonth);
std::wstring day((wchar_t*)st.wDay);
std::wstring year((wchar_t*)st.wYear);
created = month + L"/" + day + L"/" + year;
//created = temp.c_str();
//created = st.wMonth + '/' + st.wDay + '/' + st.wYear;


return created.c_str();
}

int _tmain(int argc, _TCHAR* argv[])
{
std::wstring ap(L"//S001E002/Some Folder/");
std::wstring all(L"*");
std::wstring temp = ap + all;
const wchar_t* Hotels = temp.c_str();
const wchar_t* current = L".";
const wchar_t* parent = L"..";
wchar_t* pdf = L"/*.??f\0";
wchar_t* tif = L"/*.*f";

WIN32_FIND_DATA FindFileData;
std::vector<std::wstring> folders;
std::vector<std::wstring> vs;
HANDLE hFind;

std::wcout << "Hotels Folder directory: " << Hotels << "\n";

hFind = FindFirstFile(Hotels, &FindFileData);
if (hFind != INVALID_HANDLE_VALUE)
{
do {
{
if(FindFileData.dwFileAttributes & _A_SUBDIR)
{
temp = FindFileData.cFileName;
if ( wcscmp(temp.c_str(), current) == 0 || wcscmp(temp.c_str(), parent) == 0 ) {}
else
{
folders.push_back(FindFileData.cFileName);
std::wcout << "Folder: " << FindFileData.cFileName << "\n";
//std::wcout << " equal? " << current << " : " << temp << " : " << parent << "\n";
}
}
}
} while (FindNextFile(hFind, &FindFileData));
FindClose(hFind);
}
//std::wcout << "Folder: " << str << "\n";
for (int i = 0; i < folders.size(); i++)
{
//folders[i]
temp = ap + folders[i] + pdf;
const wchar_t* _files = temp.c_str();
std::wcout << "File Directory: " << _files << "\n";
hFind = FindFirstFile(_files, &FindFileData);
if (hFind != INVALID_HANDLE_VALUE)
{
do {
{
temp = FindFileData.cFileName;
if ( wcscmp(temp.c_str(), current) == 0 || wcscmp(temp.c_str(), parent) == 0 ) {}
else
{
//std::wcout << "File: "<< FindFileData.cFileName ;
//std::wcout << " equal? " << current << " : " << temp << " : " << parent << "\n";
temp = ap + folders[i] + L"/" + FindFileData.cFileName;
vs.push_back(temp);
}
}
} while (FindNextFile(hFind, &FindFileData));
FindClose(hFind);
}
else
{
temp = ap + folders[i] + L"/";
std::wcout << temp.c_str() << " | ";
std::cout << GetLastErrorAsString() << "\n";
}
}

/*for (auto item : vs)
std::wcout << item << "\n";*/
__int64 size;
const wchar_t* created;
std::cout << "\n" << "Start File Stats" << "\n";
for (int i = 0; i < vs.size(); i++)
{
size = FileSize(vs[i].c_str());
created = Created(vs[i].c_str());
std::wcout << vs[i] << " | File size: ";
std::wcout << size ;
std::wcout << " | Created: " << created << " | Error: " << GetLastErrorAsString;
std::wcout << "\n"; // , 1 << FileSize(vs[i].c_str(), 0)
}

std::cout << "\n" << "End File Stats" << "\n";
std::cout << GetLastErrorAsString() << "\n";
std::cout << "Folder count: " << folders.size() << "\n";
std::cout << "File count: " << vs.size() << "\n";
return 0;
}

Answer
std::wstring month((wchar_t*)st.wMonth);
std::wstring day((wchar_t*)st.wDay);
std::wstring year((wchar_t*)st.wYear);
created = month + L"/" + day + L"/" + year;

You cannot use casting to convert integer to string. These two data types are very different. You could use casting to convert int to double etc. but not this. Use std::to_wstring instead. Remove reference to c_str for error strings and created, so you have

std::wstring created =
    std::to_wstring(st.wMonth) + L"/" +
    std::to_wstring(st.wDay) + L"/" +
    std::to_wstring(st.wYear);

GetLastErrorAsString() returns ANSI string, while the rest of the program is in Unicode. You try to fit it in by using the following:

std::wcout << GetLastErrorAsString << "\n"; <== error

But the result is meaningless. You should make everything Unicode. Also, GetLastErrorAsString should not return .c_str()

Moreover, do not call GetLastError() unless the function fails or if documentation indicates that calling GetLastError() is useful.

if (FindFileData.dwFileAttributes & _A_SUBDIR)

The correct flag to use here is FILE_ATTRIBUTE_DIRECTORY. See File Attribute Constants


__int64 FileSize(const wchar_t* name)
{
    WIN32_FILE_ATTRIBUTE_DATA fad;
    if (!GetFileAttributesEx(name, GetFileExInfoStandard, &fad))
        return -1; 

    LARGE_INTEGER size;
    size.HighPart = fad.nFileSizeHigh;
    size.LowPart = fad.nFileSizeLow;
    return size.QuadPart;
}

std::wstring Created(const wchar_t* name)
{
    WIN32_FILE_ATTRIBUTE_DATA fad;
    std::wstring created;
    SYSTEMTIME st;

    if (!GetFileAttributesEx(name, GetFileExInfoStandard, &fad))
    {
        std::wstring error(L"Error");
        // error condition, could call GetLastError to find out more
        return error; 
    }

    if (!FileTimeToSystemTime(&fad.ftCreationTime, &st))
    {
        std::wstring error(L"Error getting created Time");
        // error condition, could call GetLastError to find out more
        return error; 
    }

    created =
        std::to_wstring(st.wMonth) + L"/" +
        std::to_wstring(st.wDay) + L"/" +
        std::to_wstring(st.wYear);
    return created;
}

int main()
{
    std::wstring ap(L"//S001E002/Some Folder/");
    std::wstring all(L"*");
    std::wstring temp = ap + all;
    const wchar_t* Hotels = temp.c_str();
    wchar_t* pdf = L"/*.??f\0";

    WIN32_FIND_DATA FindFileData;
    std::vector<std::wstring> folders;
    std::vector<std::wstring> vs;
    HANDLE hFind;

    std::wcout << "Hotels Folder directory: " << Hotels << "\n";

    hFind = FindFirstFile(Hotels, &FindFileData);
    if (hFind != INVALID_HANDLE_VALUE)
    {
        do 
        {
            if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            {
                if (wcscmp(FindFileData.cFileName, L".") == 0 || wcscmp(FindFileData.cFileName, L"..") == 0)
                    continue;
                folders.push_back(FindFileData.cFileName);
                std::wcout << "Folder: " << FindFileData.cFileName << "\n";
            }
        } while (FindNextFile(hFind, &FindFileData));
        FindClose(hFind);
    }

    for (int i = 0; i < (int)folders.size(); i++)
    {
        temp = ap + folders[i] + pdf;
        const wchar_t* _files = temp.c_str();
        std::wcout << "File Directory: " << _files << "\n";
        hFind = FindFirstFile(_files, &FindFileData);
        if (hFind != INVALID_HANDLE_VALUE)
        {
            do 
            {
                if (wcscmp(FindFileData.cFileName, L".") == 0 || wcscmp(FindFileData.cFileName, L"..") == 0)
                    continue;
                temp = ap + folders[i] + L"/" + FindFileData.cFileName;
                vs.push_back(temp);
            } while (FindNextFile(hFind, &FindFileData));
            FindClose(hFind);
        }
        else
        {
            temp = ap + folders[i] + L"/";
            std::wcout << temp.c_str() << "\n";
        }
    }

    __int64 size;
    std::cout << "\n" << "Start File Stats" << "\n";
    for (int i = 0; i < (int)vs.size(); i++)
    {
        size = FileSize(vs[i].c_str());
        std::wstring created = Created(vs[i].c_str());
        std::wcout << vs[i] << " | File size: ";
        std::wcout << size;
        std::wcout << " | Created: " << created;
        std::wcout << "\n";
    }

    std::cout << "\nEnd File Stats" << "\n";
    std::cout << "Folder count: " << folders.size() << "\n";
    std::cout << "File   count: " << vs.size() << "\n";
    return 0;
}

A better way to format date/time is using std::stringstream

//additional headers
#include <sstream>
#include <iomanip>

...
std::wostringstream oss;
oss << std::setfill(L'0');
oss 
    << st.wMonth << L"/" 
    << st.wDay << L"/" 
    << st.wYear << L" " 
    << std::setw(2) << st.wHour << L":" 
    << std::setw(2) << st.wMinute << L":" 
    << std::setw(2) << st.wSecond;
created = oss.str();

or you can use Windows date/time format:

wchar_t buf[100];
GetDateFormat(0, 0, &st, 0, buf, 100);
created += buf;
created += L" ";
GetTimeFormat(0, 0, &st, 0, buf, 100);
created += buf;
Comments