2009-05-17 16 views
42

Robiłem to w C# i Delphi, ale C++ jest złe. Celem jest utworzenie pliku w bieżącym katalogu (gdzie wykonywany jest plik wykonywalny).Jak uzyskać aktualny katalog?

Mój kod:

LPTSTR NPath = NULL; 
DWORD a = GetCurrentDirectory(MAX_PATH,NPath); 
HANDLE hNewFile = CreateFile(NPath,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); 

otrzymuję wyjątek w GetCurrentDirectory().

Proszę mi powiedzieć, dlaczego otrzymałem wyjątek i jak mogę ułatwić w C++?

+2

include char getcwd (char buf, size_t wielkości); http://stackoverflow.com/questions/298510/how-to-get-the-current-directory-in-ac-program – Anuswadh

+0

możliwe duplikat [Jak mogę dostać katalog, który program jest z?] (http://stackoverflow.com/questions/143174/how-do-i-get-the-directory-that-a-program-is-running-od) – user

+2

UWAGA: aktualny katalog nie zawsze jest katalog, w którym znajduje się exe. (np. c: \ users \ me> \ dir1 \ dir2 \ runme.exe tutaj jesteś w c: \ users \ me i działa exe z \ dir1 \ dir2 \). – Mercury

Odpowiedz

97

Polecam lekturę książki o C++, zanim pójdziesz dalej, ponieważ byłoby to pomocne, aby uzyskać bardziej stabilne podstawy. Accelerated C++ autorstwa Koeniga i Moo jest doskonała.

Aby uzyskać plik wykonywalny ścieżka używać GetModuleFileName:

char buffer[MAX_PATH]; 
GetModuleFileName(NULL, buffer, MAX_PATH); 

Oto funkcja C++, który pobiera katalogu bez nazwy pliku:

#include <windows.h> 
#include <string> 
#include <iostream> 
using namespace std;; 

string ExePath() { 
    char buffer[MAX_PATH]; 
    GetModuleFileName(NULL, buffer, MAX_PATH); 
    string::size_type pos = string(buffer).find_last_of("\\/"); 
    return string(buffer).substr(0, pos); 
} 

int main() { 
    cout << "my directory is " << ExePath() << "\n"; 
} 
+4

Pamiętaj, że możesz potrzebować szerokiego znaku, np. Bufora wchar_t [MAX_PATH]; te dni ... – rogerdpack

+2

Lub 'GetModuleFileNameA' – Mikhail

+1

Aby powtórzyć, co powiedział @Mikhail, należy użyć' GetModuleFileNameA' dla kodu, który używa zestawu znaków wielobajtowych i 'GetModuleFileNameW' dla Unicode. 'GetModuleFileName' (bez' A' lub 'W') jest tak naprawdę aliasem dla dowolnego zestawu znaków, który jest ustawiony dla twojego projektu, w ten sposób ustawia się większość metod Win32 API, które używają łańcuchów. Więc jeśli masz projekt Unicode, a twoje łańcuchy są również unikodowe, to musisz tylko wywołać 'GetModuleFileName'. To samo dotyczy, jeśli twój projekt jest wielobajtowy i używa ciągów wielobajtowych. – RectangleEquals

30

GetCurrentDirectory nie przydziela miejsca dla wyniku, to do ciebie należy to zrobić.

TCHAR NPath[MAX_PATH]; 
GetCurrentDirectory(MAX_PATH, NPath); 

Również spojrzeć na Boost.Filesystem biblioteki, jeśli chcesz to zrobić C++ sposób.

+0

Hmm, NPath wskazuje na inny katalog, w jaki sposób mogę pokazać katalog, w którym znajduje się plik wykonywalny? –

+6

Bieżący katalog nie jest tym samym, co katalog wykonywalny, nawet w C# i Delphi. Być może mógłbyś wyjaśnić swoje pytanie? –

+0

John, to trochę bardziej skomplikowane i nie można po prostu odpowiedzieć w komentarzu. Być może powinieneś postępować zgodnie z radą Neila (obaj). – avakar

4

Należy podać prawidłowy zastępczy bufora. czyli:

TCHAR s[100]; 
DWORD a = GetCurrentDirectory(100, s); 
2

GetCurrentDirectory() pobiera aktualny katalog, czyli tam, gdzie jest wywoływana exe ​​z. Aby uzyskać lokalizację exe, użyj GetModuleFileName (NULL ...). jeśli masz uchwyt do exe, lub możesz wyprowadzić go z GetCommandLine(), jeśli nie.

Jak wskazuje pan Butterworth, nie potrzebujesz uchwytu.

+3

W rzeczywistości nie potrzebujesz prawdziwego uchwytu - uchwyt NULL otrzymuje nazwę pliku wykonywalnego ze ścieżką. –

-1

Aby znaleźć katalog, w którym plik wykonywalny jest, można użyć:

TCHAR szFilePath[_MAX_PATH]; 
::GetModuleFileName(NULL, szFilePath, _MAX_PATH); 
3

Proszę nie zapomnieć, aby zainicjować swoje bufory do coś przed ich wykorzystaniem. I tak samo ważne, dać przestrzeń bufory łańcuchowe dla kończącego zerowej

TCHAR path[MAX_PATH+1] = L""; 
DWORD len = GetCurrentDirectory(MAX_PATH, path); 

Reference

9

IMHO oto kilka ulepszeń anon's answer.

#include <windows.h> 
#include <string> 
#include <iostream> 

std::string GetExeFileName() 
{ 
    char buffer[MAX_PATH]; 
    GetModuleFileName(NULL, buffer, MAX_PATH); 
    return std::string(buffer); 
} 

std::string GetExePath() 
{ 
    std::string f = GetExeFileName(); 
    return f.substr(0, f.find_last_of("\\/")); 
} 
+0

To jest rzeczywiście różne. YOU nie podaje ścieżki do katalogu, podajesz ścieżkę do pliku, łącznie z plikiem. – dyesdyes

1
WCHAR path[MAX_PATH] = {0}; 
GetModuleFileName(NULL, path, MAX_PATH); 
PathRemoveFileSpec(path); 
1
#include <windows.h> 
using namespace std; 

// The directory path returned by native GetCurrentDirectory() no end backslash 
string getCurrentDirectoryOnWindows() 
{ 
    const unsigned long maxDir = 260; 
    char currentDir[maxDir]; 
    GetCurrentDirectory(maxDir, currentDir); 
    return string(currentDir); 
} 
3

można usunąć pliku z GetModuleFileName() z bardziej elegancki sposób:

TCHAR fullPath[MAX_PATH]; 
TCHAR driveLetter[3]; 
TCHAR directory[MAX_PATH]; 
TCHAR FinalPath[MAX_PATH]; 
GetModuleFileName(NULL, fullPath, MAX_PATH); 
_splitpath(fullPath, driveLetter, directory, NULL, NULL); 
sprintf(FinalPath, "%s%s",driveLetter, directory); 

Nadzieję, że to pomaga!

-3
String^ exePath = Application::ExecutablePath;<br> 
MessageBox::Show(exePath); 
0

fragmenty kodu z mojego projektu CAE ze środowiska programistycznego unicode:

/// @brief Gets current module file path. 
std::string getModuleFilePath() { 
    TCHAR buffer[MAX_PATH]; 
    GetModuleFileName(NULL, buffer, MAX_PATH); 
    CT2CA pszPath(buffer); 
    std::string path(pszPath); 
    std::string::size_type pos = path.find_last_of("\\/"); 
    return path.substr(0, pos); 
} 

wystarczy użyć Templete CA2CAEX lub CA2AEX która wywołuje wewnętrzne API :: MultiByteToWideChar lub :: WideCharToMultiByte.

2
#include <iostream>  
#include <stdio.h> 
#include <dirent.h> 

std::string current_working_directory() 
{ 
    char* cwd = _getcwd(0, 0) ; // **** microsoft specific **** 
    std::string working_directory(cwd) ; 
    std::free(cwd) ; 
    return working_directory ; 
} 

int main(){ 
    std::cout << "i am now in " << current_working_directory() << endl; 
} 

Nie udało mi się poprawnie użyć GetModuleFileName. Znalazłem tę pracę bardzo dobrze. właśnie testowane w systemie Windows, jeszcze nie próbuj na Linuksie :)

1

Dlaczego nikt tutaj nie rozważa używania tego prostego kodu?

TCHAR szDir[MAX_PATH] = { 0 }; 

GetModuleFileName(NULL, szDir, MAX_PATH); 
szDir[std::string(szDir).find_last_of("\\/")] = 0; 

lub jeszcze prostsze

TCHAR szDir[MAX_PATH] = { 0 }; 
TCHAR* szEnd = nullptr; 
GetModuleFileName(NULL, szDir, MAX_PATH); 
szEnd = _tcsrchr(szDir, '\\'); 
*szEnd = 0; 
Powiązane problemy