ofstream.open() устанавливает failbit в DLL, вызываемой приложением UWP

#c# #c #dll #file-io #uwp

#c# #c #dll #file-io #uwp

Вопрос:

Я посмотрел в Интернете, чтобы узнать, сталкивался ли кто-нибудь с этой проблемой, но ничего не нашел.

Итак, я пытаюсь использовать C DLL в приложении C # UWP. В этой DLL есть файл журнала, который открывается в начале кода со следующей функцией:

 #include <string>
#include <iostream>

using namespace std;

int Logger::set(string file_name, bool clear_log) {
    _file_stream.exceptions(ofstream::failbit | ofstream::badbit);
    try {
        _file_stream.open(file_name, ios_base::out | (clear_log ? ios_base::trunc : ios_base::app));
    }
    catch (ofstream::failure) {
        return -1;
    }
    _file_stream << "";
    return 0;
}
 

Вот код класса Logger:

 class Logger {
private:
    std::ofstream _file_stream;

public:
    Logger() {};
    ~Logger() { _file_stream.close(); };

    int set(std::string file_name, bool clear_log);
}
 

Теперь этот код отлично работает, когда я использую DLL в автономном режиме. Но при вызове через приложение UWP функция open() выдает исключение ofstream::failure со словами:

ios_base::failbit set: ошибка потока iostream

Сначала я подумал, что это связано со странными политиками прав доступа UWP, но после отладки file_name указывает на правильную папку пакета в AppData, поэтому здесь должно быть нормально записать файл.

В чем может быть проблема?

РЕДАКТИРОВАТЬ: я обнаружил, что по какой-то причине C file API работает так, как ожидалось. То есть следующий код успешно создает файл:

 #include <iostream>
using namespace std;

int Logger::set(string file_name, bool clear_log) {
    FILE* test = fopen(file_name.c_str(), clear_log ? "w" : "a");
    if(!test)
    {
        return -1;
    }
    fprintf(test, "");
    return 0;
}
 

Комментарии:

1. Не могли бы вы сказать мне, является ли ваша DLL проектом библиотеки динамических ссылок (DLL) или проектом DLL (Universal Windows) ?

2. Это проект DLL, часть UWP — это совсем другой проект.

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

4. @YanGu-MSFT на самом деле нет, потому что я построил всю свою библиотеку вокруг использования журнала в качестве объекта, подобного cout, и я не могу реорганизовать его, чтобы так же легко использовать C API.

Ответ №1:

Я сам разобрался в этом после более активной отладки. Где-то раньше в коде этот аналогичный (косвенный) вызов ofstream::open не завершался неудачей:

 ofstream out("out.txt", ios_base::trunc);
 

И, установив точки останова в нужном месте, я смог определить, что в этом случае значение открытого режима ( ios_base::trunc аргумент) преобразовалось в 18 (ожидаемое значение), тогда как в проблемном случае при использовании троичного оператора оно преобразовалось в странное значение 1594.

Замена троичного оператора на блок if-else решила проблему:

 int Logger::set(string file_name, bool clean_log) {
    _file_stream.exceptions(ofstream::failbit | ofstream::badbit);
    try
    {
        if (clean_log)
            _file_stream.open(file_name, ios_base::trunc);
        else
            _file_stream.open(file_name, ios_base::app);
    }
    catch (ofstream::failure)
    {
        return -1;
    }
    return 0;
}