Edificio per OneCore

Quando si usa Visual Studio per compilare codice in modalità utente per Windows 10, è possibile personalizzare le opzioni del linker per specificare le versioni specifiche di Windows. Prendere in considerazione i seguenti fattori:

  • Il file binario compilato deve essere eseguito solo sulla versione più recente di Windows? O dovrebbe essere eseguito in versioni precedenti, ad esempio Windows 7?

  • Il progetto ha dipendenze UWP ?

Ad esempio, quando si crea un nuovo progetto driver UMDF v2, Visual Studio si collega a OneCoreUAP.lib per impostazione predefinita. Ciò comporta un file binario che viene eseguito nella versione più recente di Windows e consente l'aggiunta di funzionalità UWP.

Tuttavia, a seconda dei requisiti, è possibile scegliere di collegarsi a OneCore.lib. La tabella seguente illustra gli scenari applicabili a ogni libreria:

Libreria Scenario
OneCore.lib Tutte le edizioni di Windows 7 e versioni successive, senza supporto UWP
OneCoreUAP.lib Windows 7 e versioni successive, edizioni UWP (Desktop, IoT, HoloLens, ma non Nano Server) di Windows 10

Nota

Per modificare le opzioni del linker in Visual Studio, scegliere le proprietà del progetto e passare a Linker-Input-Dipendenze>> aggiuntive.

Un subset di API Windows viene compilato in modo pulito ma restituisce errori di runtime nelle edizioni non Desktop OneCore (ad esempio Mobile o IoT).

Ad esempio, la funzione InstallApplication restituisce ERROR_ NOT_SUPPORTED nelle edizioni OneCore non Desktop. Lo strumento ApiValidator segnala anche questi problemi. La sezione successiva descrive come risolverli.

Correzione degli errori di ApiValidator tramite IsApiSetImplemented

Se il codice chiama API non universali, è possibile che vengano visualizzati gli errori ApiValidator seguenti:

  • Error: <Binary Name> has unsupported API call to <Module Name><Api Name>

    Se l'app o il driver di base devono essere eseguiti in Windows 10 e nelle versioni precedenti di Windows, è necessario rimuovere le chiamate API nella categoria precedente.

  • Error: <Binary Name> has a dependency on <Module Name><Api Name> but is missing: IsApiSetImplemented("<contract-name-for-Module>)

    Le chiamate API nella categoria precedente vengono compilate correttamente, ma potrebbero non comportarsi come previsto in fase di esecuzione, a seconda del sistema operativo di destinazione. Per superare il requisito api Layering per i driver di Windows, eseguire il wrapping di queste chiamate con IsApiSetImplemented.

In questo modo è possibile compilare il codice senza errori. In fase di esecuzione, se il computer di destinazione non dispone dell'API necessaria, IsApiSetImplemented restituisce FALSE.

Gli esempi di codice seguenti illustrano come eseguire questa operazione.

Esempio di codice: utilizzo diretto dell'API, senza valutare l'esistenza

Questo codice viene eseguito correttamente nelle versioni di Windows precedenti a Windows 10, ma in esecuzione in una OneCore edizione di Windows 10 genera un errore WTSEnumerateSessions: 78 o ERROR_CALL_NOT_IMPLEMENTED 120 (0x78).

Questo esempio di codice ha esito negativo sul requisito api layering dei driver di Windows con gli errori ApiValidator seguenti:

ApiValidation: Error: FlexLinkTest.exe has a dependency on 'wtsapi32.dll!WTSEnumerateSessionsW' but is missing: IsApiSetImplemented("ext-ms-win-session-wtsapi32-l1-1-0")
ApiValidation: Error: FlexLinkTest.exe has a dependency on 'wtsapi32.dll!WTSFreeMemory' but is missing: IsApiSetImplemented("ext-ms-win-session-wtsapi32-l1-1-0")
ApiValidation: NOT all binaries are Universal

Ecco il codice:

#include <windows.h>
#include <stdio.h>
#include <Wtsapi32.h>

int __cdecl wmain(int /* argc */, PCWSTR /* argv */ [])
{
    PWTS_SESSION_INFO pInfo = {};
    DWORD count = 0;

    if (WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pInfo, &count))
    {
        wprintf(L"SessionCount = %d\n", count);

        for (ULONG i = 0; i < count; i++)
        {
            PWTS_SESSION_INFO pCurInfo = &pInfo[i];
            wprintf(L"    %s: ID = %d, state = %d\n", pCurInfo->pWinStationName, pCurInfo->SessionId, pCurInfo->State);
        }

        WTSFreeMemory(pInfo);
    }
    else
    {
        wprintf(L"WTSEnumerateSessions failure : %x\n", GetLastError());
    } 

    return 0;
}

Esempio di codice: utilizzo diretto dell'API, dopo aver valutato l'esistenza

Questo esempio illustra come chiamare IsApiSetImplemented. In questo esempio viene superato il requisito api Layering dei driver di Windows con l'output ApiValidator seguente:

ApiValidation: All binaries are Universal

Ecco il codice:

#include <windows.h>
#include <stdio.h>
#include <Wtsapi32.h>

int __cdecl wmain(int /* argc */, PCWSTR /* argv */ [])
{
    PWTS_SESSION_INFO pInfo = {};
    DWORD count = 0;

    if (!IsApiSetImplemented("ext-ms-win-session-wtsapi32-l1-1-0"))
    {
        wprintf(L"IsApiSetImplemented on ext-ms-win-session-wtsapi32-l1-1-0 returns FALSE\n");
    }
    else
    {
        if (WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pInfo, &count))
        {
            wprintf(L"SessionCount = %d\n", count);

            for (ULONG i = 0; i < count; i++)
            {
                PWTS_SESSION_INFO pCurInfo = &pInfo[i];
                wprintf(L"    %s: ID = %d, state = %d\n", pCurInfo->pWinStationName, pCurInfo->SessionId, pCurInfo->State);
            }

            WTSFreeMemory(pInfo);
        }
        else
        {
            wprintf(L"WTSEnumerateSessions failure : %x\n", GetLastError());
        }
    }

    return 0;
}
  • Esaminare le opzioni del linker precedenti e aggiornare di conseguenza il progetto di Visual Studio.
  • Usare lo strumento ApiValidator in WDK. Questo strumento viene eseguito automaticamente quando si compila un driver in Visual Studio.
  • Usare i test di runtime per verificare che il codice in modalità utente venga eseguito come previsto nelle edizioni non desktop OneCore. Si noti che le API stub possono generare codici di errore diversi.

Vedere anche