2017-10-29 5 views
-1

LocalMon sample을 기반으로 사용자 지정 포트 모니터를 구현하고 있지만 LcmEnumPorts 구현에서 돌아 왔을 때 "데이터가 유효하지 않습니다"라는 오류 메시지가 나타나고 컴퓨터에 설치된 포트 목록이 비어 있습니다. 모니터를 제거하면 오류가 제거되고 모든 포트가 다시 나타납니다.EnumPorts를 호출 한 후 사용자 지정 포트 모니터에서 "The data is invalid"메시지가 나타납니다?

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 또는 구조의 배열 DMA 장치에 의해 지정된 기입한다. 그런 다음 마지막 배열 요소 다음의 메모리 위치에서 시작하여 함수는 배열 구조체 멤버가 가리키는 모든 문자열을로드해야합니다. 이 작업을 수행하는 방법의 예는 샘플 포트 모니터 인 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; 
}