2015-12-10 4 views
-1

Я использую функцию GetOpenFileName от Winapi, и я применяю фильтр к диалоговому окну выбора файла.C++ LPSTR и проблема с строкой с нулевыми строками

ЭТ работает отлично:

LPSTR mfilter = "Filter\0*.PDF\0"; 
ofn.lpstrFilter = mfilter; 

if(GetOpenFileName(&ofn)){ 
... 

enter image description here

ЭТА терпит неудачу (откроется диалоговое окно, но фильтры не применяются):

string mfilter = "Filter\0*.PDF\0"; 
ofn.lpstrFilter = mfilter.c_str(); 

if(GetOpenFileName(&ofn)){ 
... 

enter image description here

мне нужно использовать std:string, потому что я получаю расширение файла с помощью параметров, и этот тип облегчает конкатенацию, но я получаю проблемы несовместимости ...

Это будет мой код, если он работал, как и ожидалось (IT FAILS так же, как в предыдущем примере):

const char * ext = &(4:); //Ampersand parameter (from CA Plex) It contains "PDF" 
string mfilter = "Filter\0*." + ext + "\0"; //Final string: Filter\0*.PDF\0; 
ofn.lpstrFilter = mfilter.c_str(); 

Когда я использую этот метод, я получаю исключение во время выполнения:

string mf; 
mf.append("Filter") 
.append('\0') 
.append("*.pdf") 
.append('\0'); 

ofn.lpstrFilter = mf.c_str(); 

enter image description here

+0

Если вы установили точку останова, и вы проверяете буфер mfilter, что видите? (перед сбоем ...) –

+0

Всякий раз, когда мне приходится работать с MFC/WinAPI, я всегда использую метод MSIS. Борьба не стоит усилий. –

+0

Если вы не увидите [mcve], я сомневаюсь, что это будет продуктивно. Я могу догадаться, что вы изменяете строку или уничтожаете ее, и поэтому визуализируйте указатель недействительным. –

ответ

0

Функция GetOpenFileName использует TCHARs, а TCHARs являются WCHARs в случае UNICODE набор символов используется.

Вот пример:

std::wstring getOpenFileName(HWND hWnd, const std::wstring& sFilter) 
{ 
    wchar_t buffer[MAX_PATH] = L""; 

    OPENFILENAMEW ofn = {0}; 

    ofn.lStructSize = sizeof(ofn); 
    ofn.hwndOwner = hWnd; 
    ofn.lpstrFilter = sFilter.c_str(); 
    ofn.nFilterIndex = 1; 
    ofn.lpstrFile = buffer; 
    ofn.nMaxFile = MAX_PATH; 
    ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST; 

    if(!::GetOpenFileNameW(&ofn)) 
     return L""; 

    return buffer; 
} 

Если вы хотите параметризуем lpstrFilter на основе std::wstring вы можете просто использовать wstring::c_str(), чтобы получить LPCTSTR, который в случае UNICODEconst wchar*.

ВНИМАНИЕ: Проблема состоит в том, что std::wstring конструктор, который принимает const wchar* принимает входной сигнал является строкой С. Строки C заканчиваются «\ 0» и, таким образом, синтаксический анализ останавливается, когда он достигает символа «\ 0». Чтобы компенсировать это, вам нужно использовать конструктор , который принимает два параметра указатель на массив символов и длину. Вы можете также использовать метод string::push_back() для добавления NULL.

std::wstring sFilter = L"PDF Files"; 
sFilter.push_back('\0'); 
sFilter.append(L"*.pdf"); 
sFilter.push_back('\0'); 
+1

Единственная проблема, с которой я столкнулся, - динамически устанавливать 'ofn.lpstrFilter'. Расширение файла передается через параметр, и мне нужно применить этот фильтр расширения к диалоговому окну при его открытии. Как я вижу, вы устанавливаете фильтры как литеральную строку, и именно так это работает для меня, как показывает первый пример, но это не решение.Как бы вы установили строку фильтра динамически с параметром, всегда содержащим нуль-терминаторы? Благодарю. – ProtectedVoid

+0

Это не ответ. Из рабочих примеров видно, что ОП использует только функции ANSI. – andlabs

+0

Это не очевидно и др. В 2015 году использование символьного набора ASCII и не использование UNICODE является преступлением. –

2

С

string mfilter = "Filter\0*.PDF\0"; 

вы звоните в std::string застройщик, который завершает строку в первой \0.

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

string mfilter = "Filter\0*.PDF\0"; 
cout << "string:" << mfilter << " len: " << mfilter.length() << endl; 

печатает

string: Filter len: 6 

Строка не строится только до первого \0 терминатора. Строка состоит только из слова «Фильтр».

+0

Добавленные примеры. Благодарю. – ProtectedVoid

+0

Является ли использование встроенных NUL в 'std :: string' даже определенным? Если окажется, что вы действительно не можете сделать это с помощью 'std :: string', (чтобы ответить на ваш вопрос ниже) вам нужно будет использовать хорошее старое выделение памяти и' strcpy() '... – andlabs

+0

@andlabs Я не знаю, я знаю, что вы имеете в виду, говоря, что мне нужно определить «использование встроенных NUL». – ProtectedVoid

0
string mfilter = "Filter\0*.PDF\0"; 

Это вызывает std::basic_string конструктор, который использует с завершающим нулем строку. Он остановит разбор строки литерала на "Filter".

Попробуйте это вместо: «первый отсчет символов строки символов, на который указывает с s может содержать нулевые символы

string mfilter("Filter\0*.PDF", 13); // need double null at end 

Это называет std::basic_string конструктор, который использует

Вы должны либо сами считать символы, либо писать код обертки, если чаще встречаетесь с этой проблемой.


Связанный: std::basic_string constructors.


Что касается вашей ошибки во время выполнения:

string mf; 
mf.append("Filter") 
.append('\0') 
.append("*.pdf") 
.append('\0'); 

append()does not have an overload for a single character type. Вероятно, вы нажмете перегрузку const CharT* s с нулевым указателем.

Используйте либо append(1, '\0'), либо append("", 1), любой из которых должен добавить нулевой байт.

+0

'string mfilter (" Filter \ 0 * .PDF ", 12);' должен быть 'string mfilter (" Filter \ 0 * .PDF \ 0 ", 13);' вместо этого, потому что 'GetOpenFileName()' ожидает фильтр будет ** double ** null завершен. 'c_str()' добавит для вас один нулевой ограничитель, но данные должны содержать другой нулевой терминатор. –

+0

@RemyLebeau: Мне понравилось быть в состоянии остаться * хорошо * от WinAPI в моей карьере до сих пор. ;) Спасибо за хедз-ап. Но поскольку строковый литерал приходит с неявным нулем в конце, мне не нужно его добавлять, просто счет. (Или же 'c_str()' пропускает добавление?) – DevSolar

+0

Счет 12 не включает неявный нуль. Вы должны увеличить счет до 13, будет ли конечный null неявным или явным. 'c_str()' всегда включает свой собственный нуль в конце того, что фактически держит 'std :: string'. –

 Смежные вопросы

  • Нет связанных вопросов^_^