How to get attribute of a directory like last access and last modify - c++

I wanted to get timestamps of a directory and then show it to the user. I have written the following function, but it doesn't work when I give a full path of a directory to present its timestamp like access time. What should I do to fix this issue? I didn't know how should I open a directory and get information about its timestamps correctly for regular files my code works fine but when I wanted to extract information about directory it doesn't work.
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <strsafe.h>
BOOL GetLastWriteTimeDirectory(HANDLE arg_h_file, LPSTR arg_lpsz_string, DWORD arg_dw_size)
{
FILETIME ft_CreateTime, ft_AccessTime, ft_WriteTime;
SYSTEMTIME st_UTC, st_Local;
DWORD dw_Return;
// Retrieve the file times for the file.
if (!GetFileTime(arg_h_file, &ft_CreateTime, &ft_AccessTime, &ft_WriteTime))
{
return FALSE;
}
// Convert the last-write time to local time.
FileTimeToSystemTime(&ft_WriteTime, &st_UTC);
SystemTimeToTzSpecificLocalTime(NULL, &st_UTC, &st_Local);
// Build a string showing the date and time.
dw_Return = StringCchPrintfA(arg_lpsz_string, arg_dw_size, "%02d/%02d/%d %02d:%02d", st_Local.wMonth, st_Local.wDay, st_Local.wYear, st_Local.wHour, st_Local.wMinute);
if (S_OK == dw_Return)
{
return TRUE;
}
else
{
return FALSE;
}
}
bool AttributeLastAccessDirectory(const char* arg_path)
{
HANDLE handleFile;
char bufferLastAccessTime[MAX_PATH];
char pathDirectory[MAX_PATH];
strcpy(pathDirectory, arg_path);
handleFile = CreateFileA(pathDirectory, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (handleFile == INVALID_HANDLE_VALUE)
{
return false;
}
if (GetLastWriteTimeDirectory(handleFile, bufferLastAccessTime, MAX_PATH))
{
printf("\n\t\t");
printf("%s", "Last Accessed: \t");
printf("%s\n", bufferLastAccessTime);
CloseHandle(handleFile);
return true;
}
CloseHandle(handleFile);
return false;
}
int main(int argc, char* argv[])
{
AttributeLastAccessDirectory("C:\\Users\\mkahs\\Desktop\\Sample\\");
return 0;
}

According to the documentation for CreateFileA:
To open a directory using CreateFile, specify the FILE_FLAG_BACKUP_SEMANTICS flag as part of dwFlagsAndAttributes. Appropriate security checks still apply when this flag is used without SE_BACKUP_NAME and SE_RESTORE_NAME privileges.
Your CreateFileA function call currently sets the dwFlagsAndAttributes parameter (the sixth parameter) to 0. Setting it to FILE_FLAG_BACKUP_SEMANTICS should fix the problem.
Also, there is no need for the pathDirectory array and the call to strcpy that sets it. The arg_path parameter can be passed to CreateFileA directly.

Related

How to get information about a file for programming on windows

In Linux, we can use the function stat() to get a file info, and use the type st.mode to judge the rights of the file before we can do some operation on it. In windows, I make a lot of attempts, but little help.
At first, I want to use the function GetSecurityInfo, but I can't get the handle argument. I did find some solutions, but they all need use fopen function which is exactly what I want to avoid. Becasue I want to not do anything substantial with the file until I can determine what permissions it has.
Then I try the GetFileSecurityA function, but useless. The following is my code, and I get an error code 998 from getlasterror
void GetFilesInfo(std::string& path)
{
char *path1 = new char[1024];
strcpy(path1, path.c_str());
SECURITY_INFORMATION FLAGS = ATTRIBUTE_SECURITY_INFORMATION;
PSECURITY_DESCRIPTOR file_security_descriptor = new char[1024];
LPDWORD minNeedWords = 0;
if(GetFileSecurityA(path1, FLAGS, file_security_descriptor, 1024, minNeedWords) == 0)
error_die("GetFileInfo");
else
std::cout << file_security_descriptor << std::endl;
}
The answer is as previous comments said. I answered the question for completion.
#include <Windows.h>
void main()
{
TCHAR FileName[] = {L"C:\\Users\\Path\\To\\FileName.extension" };
DWORD LengthNeeded = 0;
SECURITY_DESCRIPTOR* sp = (SECURITY_DESCRIPTOR*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,100);
BOOL rs = GetFileSecurity(FileName, ATTRIBUTE_SECURITY_INFORMATION, sp,100,&LengthNeeded);
if (!rs)
{
DWORD e = GetLastError();
//return;
}
HeapFree(GetProcessHeap(), 0,sp);
}

Why do I get special characters when getting the source code of a website? c++

I am trying to get the source code of Barack Obama's Wikipedia page and save it to a file.
Everything works well until I open the file and see some weird characters in it:
As you can see, EOT1024 appears in the file, but it does not appear in the website's actual source code, which I checked using Google Chrome. I would like to know why this is happening, and how I can stop it from happening.
My code:
#include <iostream>
#include <windows.h>
#include <wininet.h>
#include <fstream>
int main(){
std::string textLink = "https://en.wikipedia.org/wiki/Barack_Obama";
std::ofstream file;
HINTERNET hInternet, hFile;
char buf[1024];
DWORD bytes_read;
int finished = 0;
bool e=false;
std::string waste;
file.open("data.txt",std::ios::out);
hInternet = InternetOpenW(L"Whatever", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (hInternet == NULL) {
printf("InternetOpen failed\n");
}
hFile = InternetOpenUrl(hInternet, textLink.c_str(), NULL, 0L, 0, 0);
if (hFile == NULL) {
printf("InternetOpenUrl failed\n");
}
while (!finished) {
if (InternetReadFile(hFile, buf, sizeof(buf), &bytes_read)) {
if (bytes_read > 0) {
file << bytes_read << buf;
}
else {
finished = 1;
}
}
else {
printf("InternetReadFile failed\n");
finished = 1;
}
}
InternetCloseHandle(hInternet);
InternetCloseHandle(hFile);
file.close();
}
I have the text file as I view it in Notepad++ right here:
https://drive.google.com/open?id=1Ty-a1o29RWSQiO1zTLym6XH4dJvUjpTO
I don't understand why I would get those characters in the data.txt file that I write to.
NOTE: occasionally, instead of seeing EOT1024, I even get EOT21, EOT1016, and other seemingly random characters.
You're literally writing the integer bytes_read to the file:
file << bytes_read << buf;
There's your "1024" (on the occasions that 1024 bytes were read).
Don't do that.
Furthermore, it looks like you're assuming buf is null-terminated. Instead, stream the first bytes_read of buf; that's why you have that integer.
So:
file.write(&buf[0], bytes_read);
Consult the documentation:
A normal read retrieves the specified dwNumberOfBytesToRead for each call to InternetReadFile until the end of the file is reached. To ensure all data is retrieved, an application must continue to call the InternetReadFile function until the function returns TRUE and the lpdwNumberOfBytesRead parameter equals zero.

EnumProcesses - weird behaviour

I have some weird behaviour while using WIndows API function EnumProcesses()
I have a function to determine wether a process with a certain name is already running which delivery different results wether I open the .executable manually (doubleclick) or open it via shell.
When I open it via shell it detects its running only 1 time (itself) and all is fine. When I open it using doubleclick on the .exe file however the function is returning true (already running) because the loop lists me the same process twice.
For the following code-snipped it is to mention that:
this->thisExecutableFile
contains argv[0] (initialised from running the program) to get the own process-name as you can see here:
int main(int argc, char* argv[])
{
ClientUpdate* update = ClientUpdate::getInstance();
update->setThisExecutableFile(argv[0]);
if (update->clientUpdateProcessIsRunning() == false) {
...
My goal is to find out if another instance of this process is already running and in this case exit it.
Here is my code:
bool ClientUpdate::clientUpdateProcessIsRunning()
{
bool retVal = false;
uint16_t processCount = 0;
unsigned long aProcesses[1024], cbNeeded, cProcesses;
if(!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
return false;
cProcesses = cbNeeded / sizeof(unsigned long);
for(unsigned int i = 0; i < cProcesses; i++) {
if (aProcesses[i] == 0) {
continue;
}
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, aProcesses[i]);
wchar_t buffer[50];
GetModuleBaseNameW(hProcess, 0, buffer, 50);
CloseHandle(hProcess);
std::wstring tempBuffer(buffer);
std::string tempStringBuffer(tempBuffer.begin(), tempBuffer.end());
boost::filesystem::path p(this->thisExecutableFile);
if(_strcmpi(p.filename().string().c_str(), tempStringBuffer.c_str()) == 0) {
processCount++;
if(processCount > 1) {
retVal = true;
break;
}
}
}
return retVal;
}
I know that the base-path is different when using doubleclick on the file or calling it via shell. (shell produces only filename while doubleclick passes entire path + filename into argv[0]) but I fixed that issue using
boost::filesystem::path p(this->thisExecutableFile);
p.fileName()
Which returns the correct filename (without path) in both cases I checked using print.
I am pretty puzzled why EnumProcesses() returns me the same file twice when calling the file via doubleclick instead of shell. Its not spawning two processed and in taskmanager I dont see anything like this either.
Is this a bug or I need to know something about the method I couldnt find in docs?
Thanks to the hint by Richard Critten I was able to fix it. My method is much smaller now and easier. (Also probably also alot more performant then scanning entire process-stack.) :D
Here is the solution
bool ClientUpdate::clientUpdateProcessIsRunning()
{
HANDLE hMutex = CreateMutexA(NULL, TRUE, "client-updater-mtx");
DWORD dwErr = GetLastError();
return dwErr == ERROR_ALREADY_EXISTS;
}
Thanks!

Getting compilation error for "tlhelp32.h" in MinGW g++ compiler

I am writing a simple C++ app that checks whether a given exe file example:'a.exe' is running or not(windows OS), I have googled and found some code in the below link.
http://stackoverflow.com/questions/3355379/how-do-i-find-out-if-a-exe-is-running-in-c
The code mentioned above uses a header file "tlhelp32.h". I just copied the code and did some necessary changes then complied it in MinGW , there comes the next problem, all of the datatypes mentioned in that header files are errored out
ex: 'DWORD' does not name a type, 'LONG' does not name a type, 'WCHAR' does not name a type,'CHAR' does not name a type
I never faced this kind of issues before where an existed header file is failed to compile (yes it exist I've checked it).
really appreciate any help on this.
code below:
#include <tlhelp32.h>
int main()
{
PROCESSENTRY32 pe32 = {0};
HANDLE hSnap;
int iDone;
int iTime = 60;
bool bProcessFound;
while(true) // go forever
{
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
pe32.dwSize = sizeof(PROCESSENTRY32);
Process32First(hSnap,&pe32); // Can throw away, never an actual app
bProcessFound = false; //init values
iDone = 1;
while(iDone) // go until out of Processes
{
iDone = Process32Next(hSnap,&pe32);
if (strcmp(pe32.szExeFile,"a.exe") == 0) // Did we find our process?
{
bProcessFound = true;
iDone = 0;
}
}
if(!bProcessFound) // if we didn't find it running...
{
startProcess("C:\\MinGW\\"+"a.exe",""); // start it
}
Sleep(iTime*10); // delay x amount of seconds.
}
return 0;
}
As Richard Critten said adding "Windows.h" before "tlhelp32" resolves the issue and more over a function startprocess() in the above code has never existed so use shellexecute() to make it work
ex: ShellExecute(NULL, "open", "c:\MinGW\a.exe", NULL, NULL, SW_SHOWDEFAULT);

Can not format data in PWSTR variable to use in CopyFileW command

I am very new to this, sorry about the horrible code below. I am trying to get the default path for FOLDERID_Profile and then add "\test.exe" to the end of it. Then i need to use this as the path to copy a file to. I was able to use the pSHGetKnownFolderPath method to store the profiles directory in PWSTR user_dir . Problem is, this is not an acceptable string format for the copy function.
So i used the following code to very crudely attempt to convert it to something the copy function could use.
strcat((char *)user_dir,"\\test.exe");
test7 = (LPCWSTR)user_dir;
MessageBox(NULL,test7,L"WR test file",MB_OK);
i'm using a message box to check the path before using CopyFile(currentpath,test7,false); But this is giving me 㩃瑜獥⹴硥 . I am currently using
CopyFileW(currentpath,L"C:\\Users\\Jenia\\test.exe",false);
as a workaround, but I really need this to work on other computers too...
I know I am messing up my ANSI vs Unicode formatting again, please tell me how to best achieve this goal. Let me know if you would like me to post the entire code block, but until i run that strcat method user_dir has the correct path just no file name for copy method.
more complete code below:
#include <windows.h>
#include <shlwapi.h>
#include <stdio.h>
#include <Shlobj.h>
LPCWSTR test7 = 0;
PWSTR user_dir = 0;
HMODULE hndl_shell32;
lpSHGetKnownFolderPath pSHGetKnownFolderPath;
hndl_shell32 = LoadLibrary(L"shell32");
if (NULL != hndl_shell32)
{
pSHGetKnownFolderPath = (lpSHGetKnownFolderPath)
GetProcAddress(hndl_shell32, "SHGetKnownFolderPath");
if(pSHGetKnownFolderPath != NULL)
{
if (SUCCEEDED(pSHGetKnownFolderPath(
FOLDERID_Profile,
0,
NULL,
&user_dir)))
{
//I think this is the problem here
strcat((char *)user_dir,"\\test.exe");
test7 = (LPCWSTR)user_dir;
MessageBox(NULL,test7,L"WR test file",MB_OK);
}
}
else
{
fprintf(stderr, "Failed to locate function: %d\n",
GetLastError());
}
}
else
{
fprintf(stderr, "Failed to load shell32.dll: %d\n", GetLastError());
}
Too many errors here. You cannot strcat on pointer filled by SHGetKnownFolderPath. Assuming that all variables are Unicode, this should work with project with any character set:
LPWSTR test7 = 0;
WCHAR user_dir[MAX_PATH];
...
SHGetKnownFolderPath(... &test7);
...
wcscpy(user_dir, test7);
wcscat(user_dir, L"\\test.exe");
MessageBoxW(NULL,test7,L"WR test file",MB_OK);
Don't forget to release the pointer test7 filled by SHGetKnownFolderPath.
This shows the basic way to complete your task; you'll need to adapt it for your needs.
#include <ShlObj.h>
#include <strsafe.h>
void ShowTestPath()
{
PWCHAR user_dir = NULL;
WCHAR test_file_path[MAX_PATH];
if (FAILED(SHGetKnownFolderPath(FOLDERID_Profile, 0, NULL, &user_dir)))
return;
if (FAILED(StringCchCopyW(test_file_path, MAX_PATH, user_dir)))
{
CoTaskMemFree(user_dir);
return;
}
CoTaskMemFree(user_dir);
if (FAILED(StringCchCatW(test_file_path, MAX_PATH, L"\\test.exe")))
return;
MessageBoxW(NULL, test_file_path, L"WR test file", MB_OK);
}