c++ - 为什么 WP8.1 运行时组件会在调用 boost::filesystem::file_size() 时抛出 C++ 异常?

标签 c++ windows-phone-8 boost

将带有 Boost 代码的 C++ 移植到 WP8.x 的 Windows Phone 8.x 开发人员意识到几个 Boost 二进制库包含被禁止的 Win32 调用。因此,这些 Boost 库需要移植到 WP8.x。

Microsoft 工程师 Steven Gates 移植了几个 Boost 库(即 system、chrono、date_time、smart_ptr、signals2 和 thread)并编写了 an excellent blog描述他是如何做到的。

他没有移植的一个关键的 Boost 库是文件系统。虽然我是 WinRT 和运行时组件的新手,但我想尝试将此库移植到 Windows Phone 8.1(WP8.1 比 WP8.0 具有更少的禁止功能,并且不需要 RPAL [“受限平台允许列表”] 对于许多函数)。

我首先注释掉所有不能在 Windows Phone 8.1 下编译的文件系统源代码,达到可以使用以下 Boost b2 命令为 WP8.1 ARM 构建文件系统库的状态:

b2 toolset=msvc-12.0 windows-api=phone link=static architecture=arm filesystem

我的总体计划是一次实现一个注释掉的函数,通过最小的 WP 8.1 应用程序测试移植的代码。

我的下一步是编写一个最小的 Windows Phone 8.1 应用程序和一个 Windows Phone 运行时组件 8.1 项目,两者捆绑在一个解决方案中(运行时组件将与 Boost 库交互)。为了让它们工作,我:

  • 添加运行时组件作为对主应用程序项目的引用
  • 将 Boost 文件系统静态库链接到运行时组件
  • 在名为 GetFileSize() 的运行时组件中添加了一个应用程序可以调用的 API 函数。目的是在移植的 Boost 库中运行 boost::filesystem::file_size() 函数。
  • 将代码链接到一个 UI 按钮,当按下该按钮时,调用运行时组件以调用 GetFileSize() 函数

我遇到的问题是对 boost::filesystem::file_size() 的调用抛出异常,问题是什么并不明显。

这是我写的相关代码。

namespace MinimalWindowsRuntimeApp
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            this.NavigationCacheMode = NavigationCacheMode.Required;
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }

        private void GetFileSize_Click(object sender, RoutedEventArgs e)
        {
            String filepath = "\\Phone\\Pictures\\Camera Roll\\WP_20140106_001.jpg";
            var newObject = new WindowsRuntimeComponent1.Class1();
            newObject.GetFileSize(filepath);
        }
    }
}

当我按下 Windows Phone 屏幕上的专用按钮时,它会调用 GetFileSize_Click() 函数。此代码创建 WindowsRuntimeComponent1.Class1() 可激活类的实例并调用其 GetFileSize () 函数:

// Class1.cpp
#include "pch.h"
#include "Class1.h"
#include "boost/filesystem.hpp"

using namespace WindowsRuntimeComponent1;
using namespace Platform;

Class1::Class1()
{
}

int64 Class1::GetFileSize(Platform::String ^filepath)
{
    boost::filesystem::path p (filepath->Data ());
    __int64 filesize = (__int64) boost::filesystem::file_size (p);

    return filesize;
}

目的是让运行时组件中的 GetFileSize() 函数实例化一个 boost::filesystem::path 对象(它采用路径的宽字符字符串)并调用 boost::filesystem::file_size( ) 功能。

问题是对 file_size() 的调用抛出异常,如输出窗口所示:

First-chance exception at 0x774E59A3 in MinimalWindowsRuntimeApp.exe: Microsoft C++ exception: boost::filesystem::filesystem_error at memory location 0x0315E498.

使用 native 调试器跟踪 Boost 显示 Boost 的 operations.cpp 中的代码失败:

  BOOST_FILESYSTEM_DECL
  boost::uintmax_t file_size(const path& p, error_code* ec)
  {
    . . .
#   else  // Windows

    // assume uintmax_t is 64-bits on all Windows compilers

    WIN32_FILE_ATTRIBUTE_DATA fad;

    if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0,
        p, ec, "boost::filesystem::file_size"))
        return static_cast<boost::uintmax_t>(-1);
    . . .    
#   endif
  }

调用 Win32 API GetFileAttributesExW() 函数时发生故障。在调用时,p.c_str() 等于预期的“\Phone\Pictures\Camera Roll\WP_20140106_001.jpg”。功能,which is supported for Windows Phone 8.1 , 失败并返回 0,这会导致 Boost 的 error() 函数抛出异常。

我的两个问题是:

  1. 为什么 Win32 API GetFileAttributesExW 函数失败?
  2. 我传递给 GetFileSize 的 Windows Phone 文件路径(即“\Phone\Pictures\Camera Roll\WP_20140106_001.jpg”)是否是在 Windows Phone 上指定文件的有效方式?

非常感谢您提供的任何帮助。

最佳答案

在 Windows 上创建路径时,您需要包括驱动器号(“C:\\path\\to\\file”)。请注意,在真正的 Windows Phone 应用程序中,您永远不应该对路径进行硬编码,因为用户可以将内容移动到 SD 卡。出于同样的原因,您也不应该存储文件的绝对路径。不过你的测试没问题。

此外,您正在尝试从相机胶卷中读取数据,您不能直接这样做(您只能通过 WinRT API 读取 protected 文件)。但这里有一个示例显示它可以正常工作(从一个新的空白 C++ Windows Phone 项目中替换 App::App):

App::App()
{
  InitializeComponent();
  Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending);

  auto path = std::wstring(Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data()) + L"\\Assets\\SplashScreen.scale-240.png";
  std::wstringstream ss;
  ss << L"Path is " << path << std::endl;
  WIN32_FILE_ATTRIBUTE_DATA data{};
  if (GetFileAttributesExW(path.c_str(), GET_FILEEX_INFO_LEVELS::GetFileExInfoStandard, &data))
  {
    ss << L"Size is " << (((LONG)data.nFileSizeHigh << sizeof(DWORD)) + (LONG)data.nFileSizeLow) << std::endl;
  }
  else
  {
    ss << L"Can't get size info: " << GetLastError() << std::endl;
  }
  OutputDebugString(ss.str().c_str());
}

关于c++ - 为什么 WP8.1 运行时组件会在调用 boost::filesystem::file_size() 时抛出 C++ 异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26575220/

相关文章:

c++ - 逻辑非运算符在 boost::spirit::qi 中不起作用

c++ - 从 map-C++ 中检索字符串时出现逻辑错误

c++ - 关于引用到常量(和指针到常量)的弱语义

c++ - 使用相等运算符初始化对象

xaml - 实现Windows Phone搜索界面

c++ - boost::log 是否可以在每次应用程序运行时旋转文件?

c++ - 如何在Eclipse CDT中选择文件进行调试?

c# - 我可以轻松地将 Windows 应用商店桌面应用程序转换为通用应用程序或手机应用程序吗?

c# - 在列表框 Windows Phone 8 中启用虚拟化

qt - 配置 Qt Creator 以在 Windows 上使用 Boost