Windows Phone 8.x开发人员将带有Boost代码的C++移植到WP8.x,他们知道几个Boost二进制库包含被禁止的Win32调用。因此,这些Boost库需要移植到WP8.x.
微软工程师Steven Gates移植了几个Boost库(即system、chrono、date_time、smart_ptr、signals2和thread),并写了一篇出色的博客来描述他是如何做到这一点的
他并没有移植的一个关键的Boost库是文件系统。虽然我是WinRT和运行时组件的新手,但我想尝试将此库移植到Windows Phone 8.1(WP8.1的禁用功能比WP8.0少,并且许多功能不需要RPAL["受限平台允许列表"])。
我首先注释掉了所有没有在WindowsPhone8.1下编译的文件系统源代码,达到了可以使用以下Boostb2命令为WP8.1ARM构建文件系统库的状态:
b2 toolset=msvc-12.0 windows-api=phone link=static architecture=arm filesystem
我的总体计划是一次实现一个注释掉的函数,通过一个最小的WP8.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_140106_001.jpg"。Windows Phone 8.1支持的函数失败并返回0,这导致Boost的error()函数引发异常。
我的两个问题是:
- 为什么Win32 API GetFileAttributesExW函数失败
- 我传递给GetFileSize的Windows Phone文件路径(即"\Phone\Pictures\Camera Roll\WP_20140106_001.jpg")是在Windows Phone上指定文件的有效方式吗
非常感谢你能给予的任何帮助。
在Windows上创建路径时,需要包含驱动器号("C:\\path\\to\\file")。请注意,在真正的Windows Phone应用程序中,您永远不应该硬编码路径,因为用户可以将内容移动到SD卡。出于同样的原因,您也不应该存储文件的绝对路径。不过对你的测试来说没问题。
此外,您正在尝试从Camera Roll读取,这是无法直接完成的(您只能通过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());
}