2017-10-29 7 views
-1

LocalMon sampleに基づいてカスタムポートモニタを実装していますが、LcmEnumPortsの実装から戻ったときに「データが無効です」というエラーが表示され、コンピュータにインストールされているポートの一覧が空です。モニターを取り外すとエラーが解消され、すべてのポートが再び表示されます。EnumPortsを呼び出した後、カスタムポートモニターで「データが無効です」というメッセージが表示されるのはなぜですか?

Operation could not be completed (error 0x0000000d). The data is invalid.

なぜ?私は戻ってくる構造が一貫しており、割り当てられたバッファーに収まることを確認しました。 LcmEnumPorts

実装例:それはどこでも文書化する表示されませんが

_Success_(return != FALSE) 
BOOL WINAPI LcmEnumPorts(
    _In_      HANDLE hMonitor, 
    _In_opt_     LPWSTR pName, 
           DWORD Level, 
    _Out_writes_bytes_opt_(cbBuf) 
           LPBYTE pPorts, 
           DWORD cbBuf, 
    _Out_      LPDWORD pcbNeeded, 
    _Out_      LPDWORD pcReturned 
    ) 
{ 
    UNREFERENCED_PARAMETER(pName); 
    UNREFERENCED_PARAMETER(hMonitor); 

    if (!pcbNeeded || !pcReturned || (!pPorts && (cbBuf > 0))) 
    { 
     SetLastError(ERROR_INVALID_PARAMETER); 
     return FALSE; 
    } 
    else if ((1 != Level) && (2 != Level)) 
    { 
     SetLastError(ERROR_INVALID_LEVEL); 
     return FALSE; 
    } 

    const wchar_t szMonitorName[] = L"WDK Sample Port"; 
    const wchar_t szPortName[] = L"NUL:"; 

    size_t cbPortName = wcslen(szPortName) * sizeof(wchar_t) + sizeof(wchar_t); 
    size_t cbPortDesc = wcslen(szMonitorName) * sizeof(wchar_t) + sizeof(wchar_t); 
    size_t cbText = cbPortName + cbPortDesc; 
    size_t cbStruct = Level == 1 ? sizeof(PORT_INFO_1) : sizeof(PORT_INFO_2); 

    *pcbNeeded = (DWORD)(cbText + cbStruct); 
    *pcReturned = 0; 

    if (*pcbNeeded > cbBuf) 
    { 
     SetLastError(ERROR_INSUFFICIENT_BUFFER); 
     return FALSE; 
    } 

    if (Level == 1) 
    { 
     PPORT_INFO_1 pPort1 = (PPORT_INFO_1)pPorts; 
     LPWSTR pPortName = (LPWSTR)(pPorts + cbStruct); 
     StringCbCopy(pPortName, cbPortName, szPortName); 
     pPort1->pName = pPortName; 
    } 
    else if (Level == 2) 
    { 
     PPORT_INFO_2 pPort2 = (PPORT_INFO_2)pPorts; 

     LPWSTR pPortName = (LPWSTR)(pPorts + cbStruct); 
     StringCbCopy(pPortName, cbPortName, szPortName); 
     pPort2->pPortName = pPortName; 

     LPWSTR pPortDesc = (LPWSTR)(pPorts + cbStruct + cbPortName); 
     StringCbCopy(pPortDesc, cbPortDesc, szMonitorName); 
     pPort2->pMonitorName = pPortDesc; 
     pPort2->pDescription = pPortDesc; 

     pPort2->fPortType = PORT_TYPE_READ | PORT_TYPE_WRITE; 
     pPort2->Reserved = 0; 
    } 
    *pcReturned = 1; 

    return TRUE; 
} 
+0

downvoterさんがコメントしますか?私はこの質問に対して何が嫌なのか分かりません。 – Mitch

答えて

0

、スプーラは、複数のドライバコールの同じバッファを再利用しているようです。

ドキュメントは言う:

EnumPorts関数は、バッファがPORT_INFO_1又はPORT_INFO_2構造体の配列とPPORTによって指さ記入すべきです。 最後の配列要素に続くメモリ位置から開始すると、関数は配列の構造体メンバが指すすべての文字列をロードする必要があります。 これを行う方法の例については、サンプルポートモニタlocalmon.dllを参照してください。この関数は、pcReturnedが指し示す位置に番号を置くことによって、指定された構造体の数(サポートされているポートの数)も返す必要があります。

実際には、すべてのプリントモニタで同じバッファが再利用されているようです。毎回、上部ポインタは各PORT_INFO_1/2構造体の下に移動され、下部ポインタは各割り当てられた文字列のために上に移動されます。 localmonを確認

Diagram showing top and bottom pointers

は、それが排他的にバッファの底から文字列を割り当てを示しています。同じようにサンプルを変更すると、エラーなしで実行できます。

_Success_(return != FALSE) 
BOOL 
LcmEnumPorts(
    _In_      HANDLE hMonitor, 
    _In_opt_     LPWSTR pName, 
           DWORD Level, 
    _Out_writes_bytes_opt_(cbBuf) 
           LPBYTE pPorts, 
           DWORD cbBuf, 
    _Out_      LPDWORD pcbNeeded, 
    _Out_      LPDWORD pcReturned 
    ) 
{ 
    UNREFERENCED_PARAMETER(pName); 
    UNREFERENCED_PARAMETER(hMonitor); 

    if (!pcbNeeded || !pcReturned || (!pPorts && (cbBuf > 0))) 
    { 
     SetLastError(ERROR_INVALID_PARAMETER); 
     return FALSE; 
    } 
    else if ((1 != Level) && (2 != Level)) 
    { 
     SetLastError(ERROR_INVALID_LEVEL); 
     return FALSE; 
    } 

    const wchar_t szMonitorName[] = L"WDK Sample Port"; 
    const wchar_t szPortName[] = L"NUL:"; 

    size_t cbPortName = wcslen(szPortName) * sizeof(wchar_t) + sizeof(wchar_t); 
    size_t cbPortDesc = wcslen(szMonitorName) * sizeof(wchar_t) + sizeof(wchar_t); 
    size_t cbText = cbPortName + cbPortDesc; 
    size_t cbStruct = Level == 1 ? sizeof(PORT_INFO_1) : sizeof(PORT_INFO_2); 

    *pcbNeeded = (DWORD)(cbText + cbStruct); 
    *pcReturned = 0; 

    if (*pcbNeeded > cbBuf) 
    { 
     SetLastError(ERROR_INSUFFICIENT_BUFFER); 
     return FALSE; 
    } 

    if (Level == 1) 
    { 
     PPORT_INFO_1 pPort1 = (PPORT_INFO_1)pPorts; 
     // Changed     vvvvvvvvvvvvvvvvvvvvvvvvvvv 
     LPWSTR pPortName = (LPWSTR)(pPorts + cbBuf - cbPortName); 
     StringCbCopy(pPortName, cbPortName, szPortName); 
     pPort1->pName = pPortName; 
    } 
    else if (Level == 2) 
    { 
     PPORT_INFO_2 pPort2 = (PPORT_INFO_2)pPorts; 

     // Changed     vvvvvvvvvvvvvvvvvvvvvvvvvvv 
     LPWSTR pPortName = (LPWSTR)(pPorts + cbBuf - cbPortName); 
     StringCbCopy(pPortName, cbPortName, szPortName); 
     pPort2->pPortName = pPortName; 

     // Changed     vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 
     LPWSTR pPortDesc = (LPWSTR)(pPorts + cbBuf - cbPortName - cbPortDesc); 
     StringCbCopy(pPortDesc, cbPortDesc, szMonitorName); 
     pPort2->pMonitorName = pPortDesc; 
     pPort2->pDescription = pPortDesc; 

     pPort2->fPortType = PORT_TYPE_READ | PORT_TYPE_WRITE; 
     pPort2->Reserved = 0; 
    } 
    *pcReturned = 1; 

    return TRUE; 
} 
関連する問題