Я отлаживаю пример приложения, которое развертывает пакет приложений Windows Metro (файл «.Appx»). Это вызывает метод WinRTPackageManager.AddPackageAsyncmsgstr «что не получается с подробным кодом ошибки (извлекается из возвращаемого значения вызова после завершения операции):
ошибка 0x80070002: Windows не может зарегистрировать пакет из-за
внутренняя ошибка или нехватка памяти.
Моя цель — найти, где именно эта ошибка возникает в вызове WinRT. Я думаю, что лучший способ добиться этого — найти, где установлен код ошибки. Я делал это раньше со старым простым Win32 API, но теперь с этим новым сложным асинхронным интерфейсом на основе com я полностью потерялся.
Примеры файлов проекта можно найти в. Его основная функция выглядит так:
[MTAThread]
int __cdecl main(Platform::Array<String^>^ args)
{
wcout << L"Copyright (c) Microsoft Corporation. All rights reserved." << endl;
wcout << L"AddPackage sample" << endl << endl;
if (args->Length < 2)
{
wcout << "Usage: AddPackageSample.exe packageUri" << endl;
return 1;
}
HANDLE completedEvent = nullptr;
int returnValue = 0;
String^ inputPackageUri = args[1];
try
{
completedEvent = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
if (completedEvent == nullptr)
{
wcout << L"CreateEvent Failed, error code=" << GetLastError() << endl;
returnValue = 1;
}
else
{
auto packageUri = ref new Uri(inputPackageUri);
auto packageManager = ref new PackageManager();
auto deploymentOperation = packageManager->AddPackageAsync(packageUri, nullptr, DeploymentOptions::None);
deploymentOperation->Completed =
ref new AsyncOperationWithProgressCompletedHandler<DeploymentResult^, DeploymentProgress>(
[&completedEvent](IAsyncOperationWithProgress<DeploymentResult^, DeploymentProgress>^ operation, AsyncStatus)
{
SetEvent(completedEvent);
});
wcout << L"Installing package " << inputPackageUri->Data() << endl;
wcout << L"Waiting for installation to complete..." << endl;
WaitForSingleObject(completedEvent, INFINITE);
if (deploymentOperation->Status == AsyncStatus::Error) //Here I decided to track "deploymentOperation->Status"{
auto deploymentResult = deploymentOperation->GetResults();
wcout << L"Installation Error: " << deploymentOperation->ErrorCode.Value << endl;
wcout << L"Detailed Error Text: " << deploymentResult->ErrorText->Data() << endl;
}
else if (deploymentOperation->Status == AsyncStatus::Canceled)
{
wcout << L"Installation Canceled" << endl;
}
else if (deploymentOperation->Status == AsyncStatus::Completed)
{
wcout << L"Installation succeeded!" << endl;
}
}
}
catch (Exception^ ex)
{
wcout << L"AddPackageSample failed, error message: " << ex->ToString()->Data() << endl;
returnValue = 1;
}
if (completedEvent != nullptr)
CloseHandle(completedEvent);
return returnValue;
}
Поскольку операция (PackageManager.AddPackageAsync) должна быть асинхронной, и я не совсем уверен, как отслеживать код, выполняемый в новом потоке, я решил поискать, где была установлена переменная «deployOperation-> Status» (оказалось, что это на самом деле функция вызов) в «AsyncStatus :: Error» (или целое число 3). После того, как я прошел через множество вызовов кода и функций, я понимаю, что, когда эта переменная будет установлена или нет (кажется, это не имеет значения, НО наверняка, эта функция извлекает данные об ошибке операции), зависит от члена переменной, инициализированного недокументированный вызов функции ntdll с именем «NtGetCompleteWnfStateSubscription» по указателю. Он тоже вызывался из ntdll. Упомянутая мной переменная-член выглядит следующим образом:
struct Unknown
{
AsyncStatus /*? 32bit long*/ dw0; // it was set to '3' during the current operation as the AsyncStatus::error enum value so I think it should belong to it
DWORD dw4; //was set to 0x5F
DWORD dw8; //was set to 0x80073CF6 (some generic error)
} ;
Код в ntdll, где была вызвана функция «NtGetCompleteWnfStateSubscription», инициирует переменную, член которой имеет этот тип структуры (в сборке, сгенерированной IDA PRO):
ntdll.dll:77906200 loc_77906200: ; CODE XREF: ntdll.dll:ntdll_strncpy_s+1A3j
ntdll.dll:77906200 push 1030h
ntdll.dll:77906205 push esi ; the variable pointer
ntdll.dll:77906206 push edi
ntdll.dll:77906207 push eax
ntdll.dll:77906208 lea eax, [ebp-0Ch]
ntdll.dll:7790620B push eax
ntdll.dll:7790620C push ebx
ntdll.dll:7790620D call near ptr ntdll_NtGetCompleteWnfStateSubscription
ntdll.dll:77906212 test eax, eax ; now "[esi+2Ch] + esi" contains data from the "Unkown" structure and contains the operation error data
ntdll.dll:77906214 jns short loc_7790623F
Приведенный выше код фактически вызывается 3 раза, но с тем же указателем «esi». Итак, теперь мой вопрос заключается в том, как найти, где установлен код ошибки для извлечения с помощью этой функции. Я попытался захватить большую часть функции в ntdll, которая выглядит так, но безуспешно. Я не могу отладить NtGetCompleteWnfStateSubscription по какой-то странной причине. Любые предложения будут полезны. Я использую IDA PRO 6.5, VS 2013 U1, Windows 8.1 x64 U1.
РЕДАКТИРОВАТЬ: Если вы не хотите беспокоиться о конкретных проблемах, мой общий вопрос — как определить, где асинхронные методы WinRT устанавливают свойство «IAsyncInfo :: Status» или какая функция или метод вызывается при возникновении ошибки во время их выполнения.
Задача ещё не решена.