Get Working Directory Windows

Hi, I am reading a SFML and C++ book, but I have come to a problem. I am making a Utilities file to get the working directory but there is an error here, and I can't figure it out

Here is my code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifdef RUNNING_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <Shlwapi.h>
	inline std::string GetWorkingDirectory(){
		HMODULE hModule = GetModuleHandle(nullptr);
		if (hModule){
			char path[256];
			GetModuleFileName(hModule, path, sizeof(path));
			PathRemoveFileSpec(path);
			strcat_s(path, "\\");
			return std::string(path);
		}
		return "";
	}
#endif 
Have you tried outputting to a debug log file what is ending up in your various buffers, or using the debugger?

The only issue I've ever had with obtaining the current directory is that use of the OpenFile Dialog Box can change it.
It comes up as an error in visual studios.

1
2
GetModuleFileName(hModule, path, sizeof(path));
PathRemoveFileSpec(path);


On the GetModuleFileName it says:
Error: argument of type "char *" is incompatible with parameter of type "Utils::LPWSTR"
I get the same error in PathRemoveFileSpec

I used another pethod to get the working directory which works.
http://www.cplusplus.com/forum/general/62231/
OPs compiler wrote:
Error: argument of type "char *" is incompatible with parameter of type "Utils::LPWSTR"

This is because your compiler wants to use wide characters so you want an array of wchar_t data types: https://msdn.microsoft.com/en-us/library/cc230355.aspx

Disch has a pretty informative article on this stuff: http://www.cplusplus.com/articles/2w6AC542/
Last edited on
When working with the Win Api it's best to work with TCHAR and _T() - defined in <tchar.h>.
It will work regardless of Unicode or Multi-byte char set.
Ahhh! So your problem was the infamous Visual Studio wide character default setting? Should have known!

Easier than using the TCHAR macros as Thomas suggested is just to use wchar_t instead of char. Also, I preface most of my code with this for cases where I test compile with GCC...

1
2
3
4
5
6
#ifndef UNICODE
    #define UNICODE
#endif
#ifndef _UNICODE
    #define _UNICODE
#endif 
@freddie,

why is it easier? Imagine you have to change from Unicode to Multi-byte.
With TCHAR you can easily change the char set without changing to code.

why is it easier? Imagine you have to change from Unicode to Multi-byte


And why would you have to do that? 1998 is a long time gone. The operating system internally is wide character. All calls to 'A' suffixed Win32 functions get translated via a wrapper to the 'W' functions, which are in fact the only ones which really exist. So just calling the 'W' functions directly saves a layer of translation between the two kinds of strings. And you can save yourself the whole TCHAR mess by simply defining UNICODE and using wchar_t instead of char. And in the case of Visual Studio where its pre-defined for you if you use the IDE you don't even have to define it yourself. All you have to do is use wchar_t instead of char and plow blitherly ahead using non A/W versions of the functions such as just GetCurrentDirectory() instead of GetCurrentDirectoryA or GetCurrentDirectoryW.

But if you really need to create narrow and wide builds for some reason then by all means use the TCHAR macros and includes.
Last edited on
And why would you have to do that? 1998 is a long time gone.

@ freddie,

if you need to run your code on Windows 2000 which doesn't support Unicode. Don't laugh, I once had a pen friend on the Phillippines who didn't have the money for sth. newer. I also saw on log files of websites that there are people from poor countries like Eastern Europe or East Asia where many people still use Windows 98 or 95.

Some time ago a friend of mine had to change from Multy-byte to Unicode and I still can hear him swearing. All the changes from char to wchar_t and using L in front of ""

With TCHAR you just change the project settings and you are done.
But if this doesn't concern you just use wchar_t
It think you should consider changing the name of your function to GetExeDirectory() or similar, so it does what it says it does.

Your function returns the directory where the running executable is located, which is not always going to be the working directory. In fact, it's only located in the working directory if you change to that directory and run the exe from there, or you get the exe to programmatically change the working directory to where it's located when running.

The WinAPI call to get the current working directory is GetCurrentDirectory() and gives the same folder as _getcwd() (MSVC CRT) / getcwd()

Andy

PS As GetModuleHandle(NULL) gets the handle of the exe for the current process, which is always going to be there, it is never going to fail. So the test for NULL is not needed in this case. In fact, you can just pass NULL to GetModuleFileName() to obtain the path you require.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <Shlwapi.h>
#include <string>
#include <iostream>
#include <direct.h>

#pragma comment(lib, "shlwapi.lib")

inline std::string GetExeDirectory(){
    HMODULE hModule = GetModuleHandle(nullptr);
    if (hModule){
        char path[_MAX_PATH] = "";
        GetModuleFileNameA(hModule, path, sizeof(path));
        PathRemoveFileSpecA(path);
        strcat_s(path, "\\");
        return path;
    }
    return "";
}

inline std::string GetExeDirectory2(){
    char path[_MAX_PATH] = "";
    GetModuleFileNameA(NULL, path, sizeof(path));
    PathRemoveFileSpecA(path);
    PathAddBackslashA(path); // another path function!
    return path;
}

inline std::string GetWorkingDirectory(){
    char path[_MAX_PATH] = "";
    GetCurrentDirectoryA(sizeof(path), path);
    return path;
}

int main(){
    std::string exeDir  = GetExeDirectory();
    std::string exeDir2 = GetExeDirectory2();
    std::string wkDir   = GetWorkingDirectory();

    char path[_MAX_PATH] = "";
    const char* cwd = _getcwd(path, sizeof(path));

    std::cout << "ExeDir  = " << exeDir  << "\n"
              << "ExeDir2 = " << exeDir2 << "\n"
              << "WkDir   = " << wkDir   << "\n"
              << "cwd     = " << cwd     << "\n";

    return 0;
}


C:\Tools>bin\test.exe

ExeDir  = C:\Tools\bin\
ExeDir2 = C:\Tools\bin\
WkDir   = C:\Tools
cwd     = C:\Tools

Last edited on
Topic archived. No new replies allowed.