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

时间:2014-10-26 16:30:39

标签: c++ windows-phone-8 boost

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

微软工程师Steven Gates移植了几个Boost库(即system,chr​​ono,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 Runtime Component 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.

使用本机调试器跟踪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. Windows Phone文件路径是否传递给GetFileSize(即“\ Phone \ Pictures \ Camera Roll \ WP_20140106_001.jpg”)在Windows Phone上指定文件的有效方式?
  3. 非常感谢您提供任何帮助。

1 个答案:

答案 0 :(得分:1)

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

此外,您正在尝试从相机胶卷中读取,您无法直接读取(您只能通过WinRT API读取受保护的文件)。但是这里有一个显示它工作的示例(从一个新的空白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());
}