Подтвердить что ты не робот

Как правильно использовать GetModuleFileName?

Следующий код:

#include <iostream>
#include <Windows.h>

using namespace std;

int main ()
{   LPWSTR buffer; //or wchar_t * buffer;
    GetModuleFileName(NULL, buffer, MAX_PATH) ;
    cout<<buffer;
    cin.get();
    cin.get();

}

Должен показать полный путь, в котором выполняется программа. Но в VS 2012 я получаю ошибку:

используется неинициализированная локальная переменная 'buffer'

Что не так в коде?

4b9b3361

Ответ 1

Вам нужно указать буфер, который может содержать несколько символов;

 wchar_t buffer[MAX_PATH]; 

например.

Ответ 2

VS правильно указывает, что вы используете неинициализированный буфер - buffer var - это указатель на WSTR, но он не был инициализирован статическим буфером, и он не был выделен. Также вы должны помнить, что MAX_PATH часто недостаточно, особенно в современных системах с длинными именами путей.

Поскольку вы используете С++, было бы неплохо использовать его функции. Я могу предположить следующий код:

vector<wchar_t> pathBuf; 
DWORD copied = 0;
do {
    pathBuf.resize(pathBuf.size()+MAX_PATH);
    copied = GetModuleFileName(0, &pathBuf.at(0), pathBuf.size());
} while( copied >= pathBuf.size() );

pathBuf.resize(copied);

wstring path(pathBuf.begin(),pathBuf.end());

cout << path;

Не используйте непосредственно wstring как буфер: он не определен для непрерывного буфера в каждой реализации (но обычно это)

Ответ 3

Это общая проблема с Win32 API, функции возвращают строки в буфер ограниченного размера, и вы никогда не уверены, был ли ваш буфер достаточно большим, чтобы вместить всю строку. Как сказал kingsb, даже MAX_PATH в наши дни не является достаточно хорошей константой для путей.

Я обычно использую вспомогательную функцию для этой цели:

template <typename TChar, typename TStringGetterFunc>
std::basic_string<TChar> GetStringFromWindowsApi( TStringGetterFunc stringGetter, int initialSize = 0 )
{
    if( initialSize <= 0 )
    {
        initialSize = MAX_PATH;
    }

    std::basic_string<TChar> result( initialSize, 0 );
    for(;;)
    {
        auto length = stringGetter( &result[0], result.length() );
        if( length == 0 )
        {
            return std::basic_string<TChar>();
        }

        if( length < result.length() - 1 )
        {
            result.resize( length );
            result.shrink_to_fit();
            return result;
        }

        result.resize( result.length() * 2 );
    }
}

Какой для GetModuleFileName может использоваться следующим образом:

extern HINSTANCE hInstance;

auto moduleName = GetStringFromWindowsApi<TCHAR>( []( TCHAR* buffer, int size )
{
    return GetModuleFileName( hInstance, buffer, size );
} );

Или для LoadString так:

std::basic_string<TCHAR> LoadResourceString( int id )
{
    return GetStringFromWindowsApi<TCHAR>( [id]( TCHAR* buffer, int size )
    {
        return LoadStringA( hInstance, id, buffer, size );
    } );
}