I have a UWP project included as part of my Xamarin.Forms solution. When running the Windows App Cert Kit locally, it passes without any issues.
When submitting my app to the store, it fails the certification process with the following error:
Error Found:
The supported APIs test detected the following errors:
API FindFirstFileEx in api-ms-win-core-file-l1-2-0.dll is not supported for this application type. PInvoke.Kernel32.dll calls this API.
Impact if not fixed:
Using an API that is not part of the Windows SDK for Windows Store apps violates the Windows Store certification requirements.
How to fix:
Review the error messages to identify the API that is not part of the Windows SDK for Windows Store apps. Please note, apps that are built in a debug configuration or without .NET Native enabled (where applicable) can fail this test as these environments may pull in unsupported APIs. Retest your app in a release configuration, and with .NET Native enabled if applicable.
I have verified that my app runs in Release mode, and have verified my UWP build settings:
I tried contacting Microsoft's Chat support, but was redirected to enter an Incident Report, where I was then redirected to just ask for help on a forum or pay for advanced tech support, so I haven't been able to get any more information about whether this is a valid failure or not.
Based on the documentation found on FindFirstFileEx (https://msdn.microsoft.com/en-us/library/windows/desktop/aa364419(v=vs.85).aspx), it looks like it is supported by Windows Desktop, Store apps, and Windows Phone. My UWP app was submitted to support Desktop and Mobile families, which seems to be included in the supported clients of this function, so it is unclear as to what is causing the failure.
Any ideas on where to go from here?
Update August 14 2017: This problem should now be resolved in the Store. Please try to re-submit your apps if you hit this issue.
This is a problem in the way the WACK scan is running in the Store, and how it integrates with .NET Native.
For some background, Windows doesn't actually have an API named FindFirstFileEx
- it doesn't exist. And the way the WACK's supported API scan works is that it looks at all the APIs you call and verifies if one of the following is true:
In the case of kernel32.dll!FindFirstFileEx
, WACK sees that kernel32.dll
doesn't exist in your package so it has to check the allow-list. The allow list doesn't mention FindFirstFileEx
because it doesn't exist. Here's what does exist:
C:\Program Files (x86)\Windows Kits\10\App Certification Kit>findstr FindFirstFileEx SupportedAPIs-x64.xml
<API Name="FindFirstFileExA" ModuleName="api-ms-win-core-file-l1-1-0.dll"/>
<API Name="FindFirstFileExA" ModuleName="api-ms-win-core-file-l1-2-0.dll"/>
<API Name="FindFirstFileExA" ModuleName="api-ms-win-core-file-l1-2-1.dll"/>
<API Name="FindFirstFileExA" ModuleName="api-ms-win-core-file-l1-2-2.dll"/>
<API Name="FindFirstFileExA" ModuleName="api-ms-win-downlevel-kernel32-l1-1-0.dll"/>
<API Name="FindFirstFileExW" ModuleName="api-ms-win-core-file-l1-1-0.dll"/>
<API Name="FindFirstFileExW" ModuleName="api-ms-win-core-file-l1-2-0.dll"/>
<API Name="FindFirstFileExW" ModuleName="api-ms-win-core-file-l1-2-1.dll"/>
<API Name="FindFirstFileExW" ModuleName="api-ms-win-core-file-l1-2-2.dll"/>
<API Name="FindFirstFileExW" ModuleName="api-ms-win-downlevel-kernel32-l1-1-0.dll"/>
<API Name="FindFirstFileExA" ModuleName="kernel32.dll"/>
<API Name="FindFirstFileExW" ModuleName="kernel32.dll"/>
Note there are a bunch of entries for FindFirstFileExA
and FindFirstFileExW
, which are the APIs that actually exist. Whenever your app tries to call FindFirstFileEx
, it's actually calling one of these instead.
For C / C++ developers, the pre-processor actually replaces FindFirstFileEx
with the A
or W
version based on the existence of the UNICODE
macro.
For .NET developers, the JIT runtime (or, in .NET Native's case, the compiler) figures out whether to call the A
or W
version based on the specifics of the DllImport
attribute, such as the values of the CharSet
and ExactSpelling
properties.
And herein lies the problem - at the moment, WACK in the Store is running on .NET assemblies before the compiler has substituted the non-suffixed version with the correct suffixed version. When you run WACK on your development machine, it correctly checks the assembly after the compiler has made the substitution, so you see no errors.
The first part of the fix (which is in the works) is to add the non-suffixed versions to the allow-list. The second part of the fix is to make sure WACK runs on the post-compiled bits.