坑3:命名空间和文件名
运行时组件创建完成时,根命名空间和工程的名称是一样的,直接使用没有问题。但有的同学希望修改命名空间的名称以符合公司的命名规范,此时,有以下几点需要注意:
一个是如何修改命名空间,不仅仅要将代码中命名空间修改,还要修改工程的根命名空间,方法是打开属性窗口,单击工程,就可以看到根命名空间。这两处要保持致,否则引用的工程无法编译通过。
再一个是修改完命名空间后,编译产生的dll和winmd文件名称不同,在按文件添加完引用后,主工程可以编译通过,但是会有APPX1707的警告,并且运行时会发生崩溃。分析后发现,原来是VS默认引用的时候会用winmd文件的名称去找dll文件,而现在两个文件名称不一样,所以会找不到实现。解决方案有两种,一种是修改运行时组件工程选项,使得输出的文件名保持一致;另一种是在主工程添加完winmd文件的引用后,手动编辑一下主工程的工程文件,在引用处加入如下图所示的一行,强制指定对应的实现在哪个dll文件中。
坑4:字符串转换
C/C++实现的库中,有相当一部分还是用的std::string,没有使用宽字符,为了保证这种情况下的中文可以正确的传递不出乱码,需要对字符串进行转换。闲话不多说,直接上代码。
// UTF编码的多字节转为宽字符 std::wstring TUtf8ToUnicode(const char * pszUtf8Str, unsigned len = -1) { std::wstring ret; do { if (!pszUtf8Str) break; // get UTF8 string length if (-1 == len) { len = strlen(pszUtf8Str); } if (len <= 0) break; // get UTF16 string length int wLen = MultiByteToWideChar(CP_UTF8, 0, pszUtf8Str, len, 0, 0); if (0 == wLen || 0xFFFD == wLen) break; // convert string wchar_t * pwszStr = new(std::nothrow) wchar_t[wLen + 1]; if (!pwszStr) break; pwszStr[wLen] = 0; MultiByteToWideChar(CP_UTF8, 0, pszUtf8Str, len, pwszStr, wLen + 1); ret = pwszStr; delete[] pwszStr; } while (0); return ret; } // std::string => Platform::String Platform::String ^ Ts2ps(std::string str) { return ref new Platform::String(TUtf8ToUnicode(str.c_str()).c_str()); } // 宽字符转为UTF8编码的多字节 std::string TUnicodeToUtf8(const wchar_t* pwszStr) { std::string ret; do { if (!pwszStr) break; size_t len = wcslen(pwszStr); if (len <= 0) break; size_t convertedChars = 0; char * pszUtf8Str = new(std::nothrow) char[len * 3 + 1]; if (!pszUtf8Str) break; WideCharToMultiByte(CP_UTF8, 0, pwszStr, len + 1, pszUtf8Str, len * 3 + 1, 0, 0); ret = pszUtf8Str; delete[] pszUtf8Str; } while (0); return ret; } // Platform::String => std::string std::string Tps2s(Platform::String ^ pstr) { if (pstr == nullptr) return ""; return TUnicodeToUtf8(pstr->Data()); } |
坑5:数组在异步中怎么传
如何在接口中使用数组,可以参考 https://msdn.microsoft.com/zh-cn/library/hh700131.aspx 这篇文章。里面提到不同场景下分别用什么样的数组,讲的非常详细,这里就不再重复了,重点扒一下遇到的坑。
数组作为WinRT接口的返回值时,如果该接口是同步的,一切正常;当接口是异步的时候,编译器就会抛出
error C3952: 'Platform::Array<int,1> ': WinRT does not support 'in/out' arrays. Use 'const Array<T>^' for 'in' and 'WriteOnlyArray<T>' or 'Array<T>^*' for 'out' on public APIs
按照该提示进行修改,怎么都不好使,后经过多方求解,才知道这种情况下需要进行装箱操作才可以。示例代码出下:
IAsyncOperation<Platform::Object^>^ GetArrayAsync() { return create_async([]() -> Platform::Object^ { Array<int>^ arr1 = ref new Array<int>(10); for (int i = 0; i < arr1->Length; i++) { arr1[i] = i + 1; } Platform::Object^ a = arr1; return a; }); } |
以上是我们在开发过程中遇到的一些坑和解决方案,如有理解不当之处,请小伙伴指出来,另外小伙伴们也可以在评论中积极分享下你们遇到过哪些坑,是如何解决的,大家共同进步。