How to locate where an error arises in a "PackageManager.AddPackageAsync" method call?

1

I'm debugging an example app that deploys an Windows Metro App Package (".Appx" file). It call a WinRT method "PackageManager.AddPackageAsync" which fails with detailed error code text (retrieved from the call return value after the operation was finished):

error 0x80070002: Windows cannot register the package because of an internal error or low memory.

My target is to find where exactly this error arises in the WinRT call. I think the best way for achieving this is by finding where the error code is set. I've done this before with the old simple Win32 API but now with this new complex com-based, async Interface I got completely lost.

The example project files can be found at. Its main function looks like this:

[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;
}

As the operation (PackageManager.AddPackageAsync) should be async and am not really sure how to track the code executed in the new thread I decided to search where the "deploymentOperation->Status" variable was set (it appeared that this was actually a function call) to "AsyncStatus::Error" (or the integer 3). After I gone through a LOT of code and function calls I understand that whenever this variable will be set or no (it seems it doesn't matter BUT it's certain that this function retrieves the operation error data) depends of a member of variable initialised by an Undocumented ntdll function call named "NtGetCompleteWnfStateSubscription" by it's pointer. It was called from ntdll too. The structure of the variable member I mentioned is the following:

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)
} ;

The code in ntdll where the "NtGetCompleteWnfStateSubscription" function was called, initing the variable which member have this structure type (in assembly, IDA PRO generated):

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

The above code is actually called 3 times but with the same "esi" pointer. So now my question is how to find where the error code is set to be retrieved using this function. I tried capturing most of the function in ntdll that looks like doing this but without success. I can't debug NtGetCompleteWnfStateSubscription for some strange reason. Any suggestions will be helpful. I'm using IDA PRO 6.5, VS 2013 U1, Windows 8.1 x64 U1.

EDIT: If you don't want to bother with problem specific details my generic question is how to locate where WinRT async methods sets the "IAsyncInfo::Status" property or what function or method is called when an error arrises while executing them.

c++
debugging
assembly
windows-runtime
ida
asked on Stack Overflow Sep 23, 2014 by AnArrayOfFunctions • edited Sep 23, 2014 by AnArrayOfFunctions

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0