Asset folder path for c++ program [windows] - c++

The structure of my Release version of my c++program is
| bin
| | game.exe
| content
| | sprites
| | | asset.png
Within the code I pass the path to the asset as "../content/sprites/asset.png", but it is not found by the program. What am I doing wrong?
Extra info: I am using SLD2 as a supporting library.

You are relying on the current directory being the directory containing your binary, but this is not always true. Instead, you can do this (error and range checking omitted for brevity):
WCHAR buf = new WCHAR [32768]; // allow for long path names
GetModuleFileNameW (NULL, buf, 32768);
WCHAR sep = wcsrchr (buf, '\\');
wcscpy (sep + 1, L"..\\content\\sprites\\asset.png");
...
delete [] buf;
Edit:
If you are calling code that depends on the current directory being the one containing your binary, then you can do this instead somewhere in your initialisation code:
WCHAR buf = new WCHAR [32768]; // allow for long path names
GetModuleFileNameW (NULL, buf, 32768);
WCHAR sep = wcsrchr (buf, '\\');
*sep = 0;
SetCurrentDirectoryW (buf);
delete [] buf;
Again, I have omitted error and range checking for brevity.

Related

How get the unicode string as argument to visual C++ MFC project?

I have a Visual C++ MFC project which will open the PDF File. I need to lauch this Project EXE from Python code with file path as argument. The File path is an Unicode string e.g. u'C:\\Desktop\\Rahul\xadShikhare.pdf' ("\xad" is SOFT_HYPHEN unichar number 173, Actual file path is C:\Desktop\Rahul-Shikahre.pdf).
I want to pass this unicode string to OpenDocumentFil(LPCTSTR file_path) function of CWin class which will open the file.
How to read an unicode string (string have SHOF_HYPHE unichar) from command line in Visual C++ and store it into LPCTSTR variable?
I tried with following code but it showing error as Path not exist.
LPWSTR cmd_arg = GetCommandLineW();
//---This is for removing Application exe name from cmd_arg
wstring all_args = cmd_arg;
int position = all_args.find(L" ");
wstring file_path = L"";
if (position > 0)
{
file_path = all_args.substr(position + 1);
file_path.append(L"");
MessageBox(NULL, file_path.c_str(), L"", MB_OK);
}
//--------------
if (file_path != L"")
{
OpenDocumentFile(file_path.c_str());
}
The above code is giving the problem only if the arguments have SOFT-HYPHE as unicode char in cmd_arg string.

Why does my file/dir manipulation works fine on Windows but not on Linux?

I am trying to create a file for handling session with in a directory name "IPM" i.e my project's name.
I access this file every time a user logged in and logged out plus I also access it at some more places thus i have created this function to create a path string so as to where the file is created on different OS
std::string SessionManager::createPathString(std::string sFileName)
{
char* pPath = getenv(HOME);
std::string sUserName(pPath);
createDirectory(sUserName);
std::replace(sUserName.begin(), sUserName.end(), '\\', '/');
sUserName.append("/IPM");
sUserName.append("/");
sUserName.append(sFileName);
return sUserName;
}
I call this function to get me the file path and the function to create directory goes like this
int createDirectory(std::string sUserName)
{
sUserName += "\\IPM";
#ifdef _WIN32
int ret = _mkdir(sUserName.c_str());
#elif __linux__
int ret = mkdir(sUserName.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#endif
return ret;
}
It creates a directory on windows but fails on Linux, in case the directory or file is not present it gets created on windows, but not on Linux.
Is there any way to do it by boost, since I am new to C++ this look typical.
Yes, there is Boost.Filesystem library, that has create_directory function. You'd better use that, because it can handle different separators (like / vs \) more properly than just replacing chars in a strings from time to time.
To store path, you should then use boost::filesystem::path objects, that can created from char*, std::string or std::wstring strings, then append using operator /=, then call create_directory or any other method you need:
using namespace boost::filesystem;
path p(userName);
p /= "IPM"; // By the way, you should make this constant, don't you?
p /= sFileName;
if (!create_directory(p)) {
cerr << "Failed to create directory";
}
More complete tutorial for Boost.Filesystem is available here.

How to use CopyFile for copying a particular type of files from one folder to another

How to use CopyFile for copying specific type of files from one folder to a backup file (backup.bkp)
Example:
C:\HHH
abc.jpeg
def.txt
ghi.jpeg
I want to copy only jpeg files to the backup.bkp file
I tried the below syntax but it is not working,
CopyFile( _T("C:\\HHH\*.jpeg"),_T("C:\\Backup.bak", FALSE);
Can anyone suggest a solution for this?
CopyFile doesn't accept wild cards or copy multiple files. It can copy a single file from one fully specified place to another.
To achieve what you want you need to enumerate over the directory using FindFirstFile/FindNextFile and copy the files one by one using CopyFile. These functions take wildcards or you can ask for all files, and do the filtering yourself.
Assuming the destination directory already exists.
CopyFile simply copy one file to another one. A quick solution consists in using the standard C system function to run the command to copy the files (using copy or xcopy for example), but that gives you less control.
So sticking with CopyFile, you need to list all *.jpeg files from the HHH directory first, then copy each of them into the destination directory.
You will also often need to split/concatenate paths during the processing, and though you can do that manually by using strcpy, strcat, etc. You've better to use dedicated functions like the splitpath and makepath family of functions or equivalents.
That leads us to following sample code:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <tchar.h>
int main(void) {
WIN32_FIND_DATA File;
HANDLE hSearch;
TCHAR SourcePath[_MAX_PATH];
TCHAR SourceDrive[_MAX_DRIVE];
TCHAR SourceDir[_MAX_DIR];
TCHAR SourceFname[_MAX_FNAME];
TCHAR SourceExt[_MAX_EXT];
TCHAR DestPath[_MAX_PATH];
TCHAR DestDrive[_MAX_DRIVE];
TCHAR DestDir[_MAX_DIR];
LPCTSTR lpszFindPattern = TEXT("C:\\HHH\\*.jpeg");
_tsplitpath_s(_T("C:\\HHH\\"), SourceDrive, _MAX_DRIVE, SourceDir, _MAX_DIR, NULL, 0, NULL, 0);
_tsplitpath_s(_T("C:\\Backup.bak\\"), DestDrive, _MAX_DRIVE, DestDir, _MAX_DIR, NULL, 0, NULL, 0);
hSearch = FindFirstFile(lpszFindPattern, &File);
if (hSearch != INVALID_HANDLE_VALUE) {
do {
_tsplitpath_s(File.cFileName, NULL, 0, NULL, 0, SourceFname, _MAX_FNAME, SourceExt, _MAX_EXT);
_tmakepath_s(SourcePath, _MAX_PATH, SourceDrive, SourceDir, SourceFname, SourceExt);
_tmakepath_s(DestPath, _MAX_PATH, DestDrive, DestDir, SourceFname, SourceExt);
CopyFile(SourcePath, DestPath, FALSE);
} while (FindNextFile(hSearch, &File));
FindClose(hSearch);
}
return 0;
}
CopyFile() does not support what you are asking for. You would have to manually loop through the source directory locating the desired files and then copy them one at a time.
A better solution is to let the OS do the work for you. You can use the SHFileOperation() function for that:
SHFILEOPSTRUCT op = {0};
op.hwnd = hwnd;
op.wFunc = FO_COPY;
op.pFrom = TEXT("C:\\HHH\\*.jpeg\0"); // note the extra null terminator!
op.pTo = TEXT("C:\\Backup.bak\\\0"); // note the extra null terminator!
op.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NORECURSION | FOF_SILENT;
if (SHFileOperation(&op) != 0)
{
// error...
}
else
{
if (op.fAnyOperationsAborted)
{
// not all files copied...
}
}
On Vista and later, SHFileOperation() has been deprecated by IFileOperation, but unfortunately it does not support wildcards at all, so you would have to enumerate the files manually first, passing each file to IFileOperation::CopyItem(), or putting them in an array that you can then pass to IFileOperation::CopyItems(), and then finally call IFileOperation::PerformOperations() to perform the actual copy.

Unresolved external symbol for some function calls but not all

I'm trying to create a C++ DLL for use in a VBA program. I'm following this example and had success compiling the example code and using the resulting DLL. However, I needed to add some additional functionality to the DLL so I created a few more functions in the example code and recompiled it. I then made a test program to test my new functions. When I try to call some of the DLL functions from my test project I get linker errors similar to this:
error LNK2019: unresolved external symbol "int __stdcall PWCreateDocument(long,char *,char *)" (?PWCreateDocument##YGHJPAD0#Z) referenced in function _wmain
This error occurs when I call the functions to initialize ProjectWise, CVbaHelperApp::InitInstance(), and my custom function PWCreateDocument.
This error DOES NOT OCCUR when I call PWGetLastErrorMessage(). I am able to access this function from my test program, but not any other functions in the DLL.
I've ruled out any common linker errors such as, misspellings/incorrect types between function header and definition.
I find it strange that I can successfully call PWGetLastErrorMesssage but not any other functions.
Here is the code for my test program vbaHelperTest3.cpp:
#include "stdafx.h"
typedef long LONG;
typedef int BOOL;
int _tmain(int argc, _TCHAR* argv[])
{
char* filePath = "C:\\pwworking\\cemvn\\b2edsjga\\d0572507\\";
char* fileName = "BUMP Imagery 2009.xwms";
LONG projID = 572507;
char* errorMsg;
std::cout << "Hello World" << std::endl;
CVbaHelperApp myApp;
BOOL isInit = myApp.InitInstance();
std::cout << "Is Initialized? " << isInit << std::endl;
errorMsg = PWGetLastErrorMessage();
std::cout << "Error Message: " << errorMsg << std::endl;
BOOL results = PWCreateDocument(projID, filePath, fileName);
std::cout << "PWCreateDocument Result: " << results << std::endl;
return 0;
}
The header stdafx.h includes the header for my DLL, vbaHelper.h. This is the code for vbaHelper.h:
// vbaHelper.h : main header file for the VBAHELPER DLL
//
#include "stdafx.h"
#if !defined(AFX_VBAHELPER_H__3FBDA9E4_EE8B_4AA1_8FD0_21A0A8B6C590__INCLUDED_)
#define AFX_VBAHELPER_H__3FBDA9E4_EE8B_4AA1_8FD0_21A0A8B6C590__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
/////////////////////////////////////////////////////////////////////////////
// CVbaHelperApp
// See vbaHelper.cpp for the implementation of this class
//
class CVbaHelperApp : public CWinApp
{
public:
CVbaHelperApp();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CVbaHelperApp)
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
//}}AFX_VIRTUAL
//{{AFX_MSG(CVbaHelperApp)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
//Function definitions added by me
typedef int BOOL;
typedef long LONG;
LONG __stdcall PWGetDocumentName( LONG , LONG , VOID **);
LONG __stdcall PWGetDocumentIDs( TCHAR **, LONG *, LONG *);
BOOL __stdcall PWCreateDocument( LONG, char*, char*);
char * __stdcall PWGetLastErrorMessage(void);
#endif // !defined(AFX_VBAHELPER_H__3FBDA9E4_EE8B_4AA1_8FD0_21A0A8B6C590__INCLUDED_)
Finaly, here is the code for vbaHelper.cpp, the DLL:
/****************************************************************************
*
* ProjectWise(TM) Software Development Kit
* Sample Application
* Copyright (C) 2003 Bentley Systems, Incorporated
* All Rights Reserved
*
****************************************************************************/
/****************************************************************************
*
* Project Name: VbaHelper
*
* Project Description: This example is used in conjunction with MicroStation's
* VBA to extract a Design file's attributes.
*
* File name: VbaHelper.cpp
*
* File description: Custom Module implementation
*
****************************************************************************/
/*---------------------------------------------------------------------------
Copyright (C) 2003 Bentley Systems, Incorporated
All Rights Reserved
THIS IS AN OPEN SOURCE CODE OF BENTLEY SYSTEMS, INCORPORATED
You have a royalty-free right to use, modify, reproduce and distribute
the Sample Applications (and/or any modified version) in any way you find
useful, provided that you agree that Bentley Systems, Incorporated has no
warranty obligations or liability for any Sample Application files which
are modified.
No guarantees of performance accompany Sample Application, nor is any
responsibility assumed on the part of the author(s). The software has
been tested extensively and every effort has been made to insure its
reliability.
---------------------------------------------------------------------------*/
/****************************************************************************
*
* Include Files
*
****************************************************************************/
#include "stdafx.h"
#include "vbaHelper.h"
#include "aaatypes.h"
#include "aadmsdef.h"
#include "aawddef.h"
#include "aawindef.h"
#include "aaodsdef.h"
#include "stdtypes.h"
#include "aadmsapi.fdf"
#include "aawinapi.fdf"
#include "aawindms.fdf"
#include "aaodsapi.fdf"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define DLLEXPORT __declspec( dllexport )
#define WINAPI __stdcall
//
// Note!
//
// If this DLL is dynamically linked against the MFC
// DLLs, any functions exported from this DLL which
// call into MFC must have the AFX_MANAGE_STATE macro
// added at the very beginning of the function.
//
// For example:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // normal function body here
// }
//
// It is very important that this macro appear in each
// function, prior to any calls into MFC. This means that
// it must appear as the first statement within the
// function, even before any object variable declarations
// as their constructors may generate calls into the MFC
// DLL.
//
// Please see MFC Technical Notes 33 and 58 for additional
// details.
//
/////////////////////////////////////////////////////////////////////////////
// CVbaHelperApp
BEGIN_MESSAGE_MAP(CVbaHelperApp, CWinApp)
//{{AFX_MSG_MAP(CVbaHelperApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CVbaHelperApp construction
CVbaHelperApp::CVbaHelperApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CVbaHelperApp object
CVbaHelperApp theApp;
/*----------------------------------------------------------------------+
|
| name mcmMain_GetDocumentIdByFilePath
|
| author BSI 04/2003
|
| Description This function finds document and project
| numbers of the document specified by its path.
|
+----------------------------------------------------------------------*/
extern "C" int mcmMain_GetDocumentIdByFilePath
(
LPWSTR pchFilePath, /* i full file path to search */
long *plProNo, /* o project id */
long *plDocNo /* o document id */
);
/*----------------------------------------------------------------------+
|
| name HooksInitialize
|
| author BSI 04/2003
|
| Description Dll entry function for ProjectWise.
|
+----------------------------------------------------------------------*/
extern "C" LONG HooksInitialize
(
ULONG ulMask, // i Application Mask
LPVOID lpReserved // i Reserved (must be NULL)
)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return IDOK;
}
/*----------------------------------------------------------------------+
|
| name PWGetDocumentName
|
| author BSI 04/2003
|
| Description A function that will populate documentName for the given
| DOCUMENT_ID.
|
| Return SUCCESS - The path and file name of the specified document
| were built successfully.
|
| -1 - Failed to build the path and file name of the
| specified document.
|
+----------------------------------------------------------------------*/
LONG WINAPI PWGetDocumentName
(
LONG PROJECT_ID, /* i Project ID*/
LONG DOCUMENT_ID, /* i Document ID */
VOID **documentName /* o Document Name*/
)
{
BOOL status = FALSE;
TCHAR tempDocName[MAX_STRING];
// Extract the document's name
status = aaApi_GetDocumentFileName (PROJECT_ID, DOCUMENT_ID, tempDocName, MAX_STRING);
_tcscpy ((TCHAR*)(*documentName), tempDocName);
return (status == TRUE ? SUCCESS : -1);
}
/*----------------------------------------------------------------------+
|
| name PWGetDocumentIDs
|
| author BSI 04/2003
|
| Description A function that will return the document's
| Project and Document IDs.
|
| Return SUCCESS or error number
|
+----------------------------------------------------------------------*/
LONG WINAPI PWGetDocumentIDs
(
TCHAR **fileName, /* i Desgin File Name */
LONG *ProjectID, /* o Project ID */
LONG *DocumentID /* o Document ID */
)
{
return mcmMain_GetDocumentIdByFilePath (*fileName, ProjectID, DocumentID);
}
/*----------------------------------------------------------------------+
|
| name convertCharArrayToLPCWSTR
|
| author MY CUSTOM FUNCTION 10/2015
|
| Description Converts regular string to LPCWSTR, which
| is required by projectwise.
|
| Return The converted string.
|
+----------------------------------------------------------------------*/
wchar_t *convertCharArrayToLPCWSTR(const char* charArray)
{
wchar_t * wString=new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096);
return wString;
}
/*----------------------------------------------------------------------+
|
| name PWCreateDocument
|
| author MY CUSTOM FUNCTION 10/2015
|
| Description A function that will create a new document in the
| specified PW project.
|
| Return SUCCESS or error number
|
+----------------------------------------------------------------------*/
BOOL WINAPI PWCreateDocument
(
LONG PROJECT_ID, /* i Project ID*/
char* PATH_NAME, /* path of document */
char* FILE_NAME /* name of document */
)
{
LONG docID = 0L;
//LONG lngAppID = aaApi_GetFExtensionApplication(L"xwms");
LONG lngAppID = aaApi_GetFExtensionApplication(L"pdf");
LONG lngWorkSpaceID = aaApi_GetWorkspaceProfileId(PROJECT_ID, 0);
LPCWSTR _path_name = convertCharArrayToLPCWSTR(PATH_NAME);
LPCWSTR _file_name = convertCharArrayToLPCWSTR(FILE_NAME);
WCHAR strWorkingDir[_MAX_PATH]; // for checked out file locationmemset (strWorkingDir, '\0', _MAX_PATH);
BOOL status = aaApi_CreateDocument(
&docID, //new document's ID
PROJECT_ID, //Passed in project ID
0, //default
0, //default
0, //default
lngAppID, //Applicaiton ID
0, //no department
lngWorkSpaceID, //workspace profile
_path_name, //source file
_file_name, //Name of file in PW, must be the same as Document Name
_file_name, //Document Name
NULL, //Document description
NULL, //Document Version
FALSE, //Specifies that this document is checked out to the user after it is create in PW.
AADMSDOCCREF_DEFAULT, //Checks documentaiton for flags
//_path_name, //location of the file if checked out
strWorkingDir,
_MAX_PATH - 1, //make sure the buffer is large enough
0 //New attribute ID in environment if created
);
//???
//long errorID=aaApi_GetLastErrorID();
//LPCWSTR errorStr = aaApi_GetLastErrorDetail();
return status;
}
/*----------------------------------------------------------------------+
|
| name PWGetLastErrorMessage
|
| author BSI 04/2003
|
| Description A function that will return the last ProjectWise Error
| message.
|
| Return Last Error message.
|
+----------------------------------------------------------------------*/
char * WINAPI PWGetLastErrorMessage
(
void
)
{
char *errorMsg;
TCHAR TerrorMsg [MAX_STRING];
errorMsg = (char *)malloc (sizeof (char) *MAX_STRING);
_tcscpy (TerrorMsg, aaApi_GetLastErrorMessage());
aaApi_UnicodeToAnsiStr (TerrorMsg, errorMsg,MAX_STRING);
return errorMsg;
}
/*----------------------------------------------------------------------+
|
| name PWGetDocumentAttributes
|
| author BSI 04/2003
|
| Description A function that will return the documents attributes.
|
| Return SUCCESS or -1 if error.
|
+----------------------------------------------------------------------*/
LONG WINAPI PWGetDocumentAttributes
(
LONG ProjectID, /* i Project ID */
LONG DocumentID, /* i Document ID */
void **AttributeData /* o Document attributes */
)
{
CString message;
LONG status = SUCCESS;
LONG lEnvId = aaApi_GetEnvId (0);
LONG lTabNo = aaApi_GetEnvNumericProperty (ENV_PROP_TABLEID, 0);
LONG count = -1;
int rowCount = -1;
/* Select environment for given project */
status = aaApi_SelectEnvByProjectId (ProjectID);
if (status == -1 || status == 0)
{
return -1;
}
else
{
// Select the documents Attribute Data
rowCount = aaApi_SelectLinkDataByObject (
lTabNo, /* i Table identifier (required) */
AADMSLDT_DOCUMENT, /* i Reference Item type */
ProjectID, /* i First item identifier */
DocumentID, /* i Second item identifier */
NULL, /* i Where statement (optional) */
&count, /* io Column count in lplColumnIds */
NULL, /* i Columns to fetch (NULL - all) */
0 /* i Flags (AADMSLDSF_XXX) */
);
if (rowCount <= 0)
return -1;
for (int colIndex= 0; colIndex<count; colIndex++)
{
message += aaApi_GetLinkDataColumnStringProperty (LINKDATA_PROP_COLUMN_NAME, colIndex);
message += ": ";
message += aaApi_GetLinkDataColumnValue (0, colIndex);
message +="\n";
}// end for
_tcscpy ((TCHAR*)(*AttributeData), message);
}
return SUCCESS;
}
/*----------------------------------------------------------------------+
|
| name InitInstance
|
| author BSI 04/2003
|
| Description Initialize the PW API
|
| Return Nonzero if initialization is successful; otherwise 0.
|
+----------------------------------------------------------------------*/
BOOL CVbaHelperApp::InitInstance()
{
// Initialize PW
aaApi_Initialize (AAMODULE_ALL);
return CWinApp::InitInstance();
}
/*----------------------------------------------------------------------+
|
| name ExitInstance
|
| author BSI 04/2003
|
| Description Remove the hook function on exit.
|
| Return 0 for success or > 0 for error.
|
+----------------------------------------------------------------------*/
int CVbaHelperApp::ExitInstance()
{
return CWinApp::ExitInstance();
}
Edit Update
I realized that my header file does not need function definitioins. The project uses a vbaHelper.def file to define the functions. I removed the definitions from the header and now have different errors:
error C3861: 'PWGetLastErrorMessage': identifier not found
error C3861: 'PWCreateDocument': identifier not found
Edit Number 2
I do not believe this should qualify as a duplicate of other Unresolved external symbol questions as I have vetted all the common reasons for this error. Also, I have now resolved the linker error and I'm looking for reason why I would be receiving "identifier not found" errors.
You need to append your function definitions with extern "C" if you want to be able to call them from c. You already have such an example in the code that you've posted.
extern "C" LONG HooksInitialize
BOOL WINAPI PWCreateDocument
is should be
BOOL DLLEXPORT PWCreateDocument

Weird characters in a std::vector<TCHAR*>

Trying to get all sub directories, and eventually all files in sub directories, and I'm passing a std::vector as a reference to a function that actually gets all of the directories. I can cout the cFileName inside the function but once it returns the main the vector has weird characters.
Currently have my Character Set to use Unicode. When I was using multibyte it would actually print weird characters, now it prints nothing. The vector does have something in it (directories.size() returns a value > 0)
Can't really think of anything else. Hopefully this was a good question lol. Thanks
#include <iostream>
#include <vector>
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
// Declare function prototypes
DWORD listDirectories(std::vector<TCHAR*>&);
// Global variable that holds the current working path of the program
TCHAR buffer[MAX_PATH];
void main()
{
// Declare variables, dwCount for return value from listDirectories, directories stores all sub directories, cDirectory stores current directory
DWORD dwCount;
//std::vector<TCHAR*> directories;
std::vector<TCHAR*> directories;
TCHAR cDirectory[MAX_PATH];
// Get current directory
GetCurrentDirectory(MAX_PATH, buffer);
// Set cDirectory (current directory) to buffer (ATM is current directory) + add \\ to the end and make it the working directory
_tcscpy_s(cDirectory, buffer);
_tcscat_s(cDirectory, L"\\*");
// dwCount is count of how many directories found, to be used later
dwCount = listDirectories(directories);
// Range for loop to print each value in the std::vector<TCHAR*> directories
for (auto tStr : directories) {
// Doing wcout here prints weird characters.
std::wcout << tStr << std::endl;
}
std::cin.get();
} // end void main()
DWORD listDirectories(std::vector<TCHAR*> &directories)
{
// Declare variables, count used for number of directories, hFind for FindFirstFile, data used to store file data
DWORD count = 0;
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA data;
TCHAR currentDir[MAX_PATH];
// Copy the current working directory into currentDir, will be used for subDir
_tcscpy_s(currentDir, buffer);
// Append "\\*" to buffer to make it a working directory
_tcscat_s(buffer, L"\\*");
// Find first file in the current working directory, storying data in data as a reference
hFind = FindFirstFile(buffer, &data);
// If hFind is not an invalid handle
if (hFind != INVALID_HANDLE_VALUE) {
// Go through each file in the directory
do
{
// If the file attributes is a directory
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// Create a sub directory
TCHAR subDir[MAX_PATH];
// Fill subDir with current directory + "\\" + dir name
_tcscpy_s(subDir, currentDir);
_tcscat_s(subDir, L"\\");
_tcscat_s(subDir, data.cFileName);
// Fill subDir with current directory + "\\" + dir name
//sprintf_s(subDir, "%s%s%s", currentDir, "\\", data.cFileName);
// Add directory to my directories (std::vector<TCHAR*>) if count > 1, because I don't want the "." and ".." directories
if (count > 1){
directories.push_back(subDir);
// Doing wcout here prints the subDir just fine and works properly
std::wcout << subDir << std::endl;
}
// Add 1 to count, used as the return for how many directories found in the current directory
count++;
}
} while (FindNextFile(hFind, &data) != 0);
}
// Return count of directories found. -2 to get rid of the "." and ".." directories
return (count - 2);
} // end DWORD listDirectories(std::vector<TCHAR*>&)
In your listDirectories() function
TCHAR subDir[MAX_PATH];
...
directories.push_back(subDir);
subDir is an array local to the do ... while loop within the function and its lifetime ends with every iteration of the loop.
Change std::vector<TCHAR*> directories; to std::vector<std::basic_string<TCHAR>> directories; and your code should work correctly. Now you'll make a copy of the directory name and add that to the vector.
Another alternative is to forget about all the TCHAR stuff and just use the wide character versions of everything when dealing with the Windows API.
std::vector<std::wstring> directories;
wchar_t cDirectory[MAX_PATH];
...
hFind = FindFirstFileW(buffer, &data);
and so forth