Почему я не могу использовать CString в качестве возвращаемых типов или параметров в MFC DLL, созданной для Windows CE?

У меня есть библиотека, созданная для проекта Windows рабочего стола. Это сделано в MFC VC ++ кем-то другим, и это работает правильно. Я буду использовать одну конкретную функцию из библиотеки в качестве примера для объяснения ситуации.

Пример функции выглядит так:

CString GetFulPath(); // .h file  

В файле cpp

CString CwFolderBrowser::GetFullPath()
{
    CString path;
    if(this->M_pIDLIST!=NULL)
    {
        LPTSTR fullPath=path.GetBuffer(MAX_PATH);
        ::SHGetPathFromIDList(this->M_pIDLIST, fullPath);   //ITEMIDLISTからパスを得る
        path.ReleaseBuffer();
    }
    return path;
}

Теперь я могу включить эту библиотеку в свой проект и сделать что-нибудь вроде:

CwFolderBrowser cFolderBrowser;
if(cFolderBrowser.ShowDialog() == TRUE)
     cPath = cFolderBrowser.GetFullPath();

Откроется диалоговое окно браузера папок, и я смогу выбрать папку. Он отлично работает в окнах рабочего стола.

В настоящее время я работаю на устройстве Windows CE. Мы преобразовали библиотеку для использования с Windows CE, удалив неподдерживаемые функции и прочее. Библиотека компилируется и строится правильно, без ошибок.

Затем я создаю проект интеллектуального устройства MFC, включаю преобразованную библиотеку, ее h-файл и файлы lib и устанавливаю соответствующие каталоги для dll. Проект строится нормально. Я также могу правильно # включить файл h библиотеки.

Проблема возникает, как только я вызываю функцию GetFullPath:

cPath = cFolderBrowser.GetFullPath();  

Это дает мне неразрешенную ошибку внешней ссылки! Intellisense показывает эту функцию в своем списке, и я могу выбрать ее и все остальное. Но тщетно.

Как ни странно, если я изменю библиотеку и изменю подпись GetFullPath (), как показано ниже,

LPCTSTR GetFulPath(); // .h file  LPCTSTR instead of CString

В файле cpp

LPCTSTR CwFolderBrowser::GetFullPath()  // Return type changed to LPCTSTR  
{                                       // instead of CString 
     ...                                // Body modified accordingly
}

тогда неразрешенная ошибка внешней ссылки исчезает, и она работает!

Я озадачен этим странным поведением, потому что я могу нормально использовать CString в проекте MFC Smart Device, и ошибок нет. Ошибка ссылки появляется только тогда, когда я пытаюсь вызвать функции из библиотеки (и других подобных библиотек) dll. В то же время BOOL, int и т. Д., Похоже, не имеют проблем как возвращаемые типы функций.

Конечно, я могу пройтись по каждой библиотеке и изменить каждый экземпляр CString return на LPCTSTR, но это было бы очень большим изменением. Я хотел бы знать, почему CString отлично работает в проекте, а также dll на рабочем столе, тогда как на Win CE он работает в проекте, но не в DLL (в то же время сама DLL компилируется нормально без ошибок, если она использует CString или LPCTSTR!).

Итак, в основном, Я хотел бы сохранить функцию CString, если это возможно, и хотел бы знать причину, по которой это происходит. Точно такая же ошибка возникает и в других библиотеках.

Любая помощь приветствуется. Спасибо.

ОБНОВЛЕНИЕ: Я видел страницу об ATL и MFC 7.0, на которой говорилось об использовании параметра / Zc: wchat_t. Я проверил проект Dll, а также свое приложение. Оба используют ту же опцию «Обрабатывать wchar_t как встроенный тип» как «Да». Итак, этот вариант подходит. Далее, как я уже упоминал выше, изменение функции return на LPCTSTR работает. Ошибка исчезает. Все идет хорошо, пока я не конвертирую возвращенный LPCTSTR обратно в CString. CString оказывается пустым / нулевым. Это происходит как внутри самого кода dll, так и в коде моего приложения.

ОБНОВЛЕНИЕ 2: благодаря Майклу и Коди я изменил функцию на LPCTSTR и убедился, что значения не выходят за рамки, прежде чем я смогу использовать их, как они предлагали. Теперь проблема пустого / нулевого значения решена, и я могу правильно получить значения пути.

Остается проблема в том, что мне нужно преобразовать все функции CString в LPCTSTR, что не совсем возможно. Я хотел бы сохранить функции как CString.


person PRinCEKtd    schedule 31.05.2016    source источник


Ответы (1)


Это классическая проблема, которую часто задают здесь, на SO.

Это не может работать:

LPCTSTR CwFolderBrowser::GetFullPath()
{
    CString path;
    if(this->M_pIDLIST!=NULL)
    {
        LPTSTR fullPath=path.GetBuffer(MAX_PATH);
        ::SHGetPathFromIDList(this->M_pIDLIST, fullPath);  
        path.ReleaseBuffer();
    }
    return (LPCTSTR)path;  // << here you return a pointer to the zero 
                           //    terminated string in the path object,  
}                          //    but path will be deleted as soon as it goes
                           //    out of scope

Возможно, в некоторых случаях функция работает, потому что память удаленного объекта CString еще не была перезаписана.

Вы должны сделать это (для простоты здесь нет обработки ошибок):

LPCTSTR CwFolderBrowser::GetFullPath(TCHAR *pathbuffer)
{
    if(this->M_pIDLIST!=NULL)
    {
        ::SHGetPathFromIDList(this->M_pIDLIST, pathbuffer);  
    }

    return (LPCTSTR)pathbuffer;
}

...
// call like this
TCHAR pathbuffer[MAX_PATH];
GetFullPath(pathbuffer);
person Jabberwocky    schedule 31.05.2016
comment
Спасибо, Майкл. Этот сработал. В случае с настольным компьютером типом возврата был CString, поэтому я думаю, что возвращение переменной «path» было нормальным. Но в случае CE, поскольку он возвращает указатель, мы должны что-то изменить ... В любом случае, я попробовал ваше предложение, и эта часть работает правильно. Остается вопрос, почему я не могу использовать CString в качестве возвращаемого типа для этой функции в случае Windows CE? - person PRinCEKtd; 31.05.2016
comment
Как показано в первом примере вопроса, это была исходная функция в Dll для настольной версии Windows. Он отлично компилируется и работает правильно. Но когда я пытаюсь скомпилировать его для Windows CE, возвращаемый тип CString вызывает ошибку Unresolved Linker, поэтому я попытался изменить его с CString на LPCTSTR. если тип возврата CString работал и в Windows CE, то я могу напрямую использовать исходную функцию, как она есть, без необходимости менять ее на LPCTSTR. - person PRinCEKtd; 31.05.2016
comment
@PRinCEKtd У меня нет ответа на этот вопрос, на самом деле у вас есть два разных вопроса. - person Jabberwocky; 31.05.2016
comment
Хммм ... Кажется, да? Стоит ли разбить вопрос на 2 разных? - person PRinCEKtd; 31.05.2016
comment
Ооо, я бы не стал этого делать. Это создает очень запутанный API. Если бы я это увидел, у меня не было бы возможности узнать, что вы возвращаете мне дескриптор того же буфера, который я передал, или другого. Обычно, когда вы возвращаете указатель из функции, это означает, что вызывающий объект становится владельцем этого указателя и несет ответственность за его уничтожение. Но поскольку у меня уже есть pathbuffer, я могу получить двойное освобождение. Мне нужно было бы прочитать документацию, чтобы быть уверенным (если она существует). Просто используйте один параметр входа / выхода. Это намного яснее. Возвращает успех как BOOL или HRESULT. - person Cody Gray; 31.05.2016
comment
Спасибо, Коди. Я понимаю вашу точку зрения ... Поскольку я передаю pathbuffer в качестве параметра, а затем возвращаю его как возвращаемое значение, у меня не будет возможности узнать, что есть что, потому что у меня уже есть pathbuffer, но я также получаю указатель в качестве возвращаемого значения. Не глядя на код, я не смог бы сказать, одинаковые они или разные. Но опять же, главный вопрос - что я могу сделать, чтобы сохранить его как CString? Есть идеи по этому поводу? - person PRinCEKtd; 01.06.2016