tutorials.de Buch-Aktion 05/2012
Like Tree1Danke
  • 1 Beitrag von Muepe32
ERLEDIGT
JA
ANTWORTEN
5
ZUGRIFFE
726
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Technipion Technipion ist offline Mitglied
    Registriert seit
    Apr 2011
    Beiträge
    11
    Hallo allerseits,
    ich bin neu hier im Forum und ich habe ein Problem: Ich programmiere seit ein paar Jahren in meiner Freizeit etwas C++ aber jetzt habe ich mir mal vorgenommen eine eigene Grafikschnittstelle zu schreiben. Ich weiß das ist ein großes Projekt aber machbar wenn man halt ein paar Wochenenden bis nachts vorm PC hockt...

    Meine Frage war jetzt: Weil ich weder auf DirectX, OpenGL, CUDA, o.a. zurückgreifen möchte wollte ich gerne direkt die Funktionen des Grafiktreibers benutzen. Eigentlich müsste man doch einfach die Treiber Dll "anzapfen" können und dann mit den gleichen Funktionen wie das Betriebssystem oder andere Schnittstellen direkt die GPU in den virtuellen Speicher schreiben lassen, oder? Kennt sich da jemand von euch aus?
    Kann man Treiber da "anzapfen"? Oder wenigstens herausfinden welche libs z.B. DirectX benutzt und dazu noch die passenden Funktionsnamen?
    Wäre echt super wenn mir jemand helfen würde.
     

  2. #2
    Avatar von Muepe32
    Muepe32 Muepe32 ist offline Mitglied Brokat
    Registriert seit
    Mar 2011
    Beiträge
    353
    Ich denke was relevant ist zu erwähnen ist, dass nicht DirectX die Funktionen des Graphikkartentreibers implementiert, sondern dass DirectX Anforderungen an den Graphikkartentreiber stellt, welche Funktionen er zu implementieren hat. DirectX fordert also gewisse Funktionen und die Graphikkartenhersteller (oder ein unabhängiger Treiberentwickler) müssen diese dann implementieren. So wird IDirect3DDevice9::SetIndices im Endeffekt einfach die Funktion SetIndices, die der Treiber exportiert aufrufen, da dies einer der Funktionen ist, die ein Treiber implementieren muss um DirectX zu unterstützen.

    Wenn du also deine wirklich eigene Schnittstelle möchtest müsstest du dafür sorgen, dass die Graphikkartenhersteller in ihren Treibern die Funktionen implementieren, die du benötigst. Wenn du die DirectX-Funktionen des Treibers ohne DirectX verwenden möchtest solltest du dir als erstes mal das Windows DDK herunterladen, damit du all die low level Sachen in einem Header hast und nicht selbst definieren musst. Anschliessend benötigst du den Pfad zum aktuellen user mode display driver (UMD). Dafür exportiert die GDI32.dll die Funktionen D3DKMTOpenAdapterFromHdc und D3DKMTQueryAdapterInfo mit KMTQAITYPE_UMDRIVERNAME. Du kannst via CreateDC und dem Adapternamen den DC erstellen um mit D3DKMTOpenAdapterFromHdc dann den HANDLE für den Adapter bekommen.

    In Code sieht das dann so aus (includepfade musst du halt entsprechend anpassen):
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    
    #include <windows.h>
    #include <dx/d3d9.h>
    #include <api/d3dumddi.h>
    #include <api/d3dkmthk.h>
     
    int main()
    {
        D3DKMT_UMDFILENAMEINFO kmInfo = 
        {
            KMTUMDVERSION_DX9,
            0
        };
     
        DISPLAY_DEVICE ddev;
        ddev.cb = sizeof(ddev);
        // Device Nummer 2 ist bei mir die richtige Graphikkarte
        EnumDisplayDevices(NULL, 2, &ddev, 0);
     
        HDC hDc = CreateDC(NULL, ddev.DeviceName, NULL, NULL);
        // Fehlerbehandlung
     
        D3DKMT_OPENADAPTERFROMHDC openHdc = 
        {
            hDc,
            0,
            0,
            0
        };
     
        NTSTATUS status = D3DKMTOpenAdapterFromHdc(&openHdc);
        // Fehlerbehandlung
        DeleteDC(hDc);
     
        D3DKMT_QUERYADAPTERINFO info =
        {
            openHdc.hAdapter,
            KMTQAITYPE_UMDRIVERNAME,
            &kmInfo,
            sizeof(kmInfo)
        };
     
        status = D3DKMTQueryAdapterInfo(&info);
        // Fehlerbehandlung
        HMODULE hDriver = LoadLibraryW(kmInfo.UmdFileName);
    }

    Nachdem du den UMD geladen hast kannst du die Funktion OpenAdapter verwenden um eine Liste von Funktionen zu erhalten, die du dann weiter verwenden kannst. Das ist relativ umständlich mit den Callbacks und den teilweise inkompatiblen Typen aber danach hast du eine Liste mit Funktionen, die unter anderem CreateDevice beinhält. Da erhälst du dann wiederum eine lange Liste mit Funktionen wie SetIndices, DrawPrimitive, usw (siehe hier). Dann bist du ready um mit der Graphikkarte zu kommunizieren. Bis und mit OpenAdapter sieht das dann so aus:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    
    #include <windows.h>
    #include <dx/d3d9.h>
    #include <api/d3dumddi.h>
    #include <api/d3dkmthk.h>
     
    HRESULT APIENTRY CALLBACK QueryAdapterInfoCallback(
      __in     HANDLE hAdapter,
      __inout  const D3DDDICB_QUERYADAPTERINFO *pData
    )
    {
        D3DKMT_QUERYADAPTERINFO info =
        {
            (D3DKMT_HANDLE)hAdapter,
            KMTQAITYPE_UMDRIVERPRIVATE,
            pData->pPrivateDriverData,
            pData->PrivateDriverDataSize
        };
     
        NTSTATUS status = D3DKMTQueryAdapterInfo(&info);
        return (status >= 0) ? S_OK : E_FAIL;
    }
     
    HRESULT APIENTRY CALLBACK GetMultisampleMethodListCallback(
      __in     HANDLE hAdapter,
      __inout  D3DDDICB_GETMULTISAMPLEMETHODLIST *pData
    )
    {
        D3DKMT_MULTISAMPLEMETHOD* pMethods = new D3DKMT_MULTISAMPLEMETHOD[pData->MethodCount];
        D3DKMT_GETMULTISAMPLEMETHODLIST list = 
        {
            (D3DKMT_HANDLE)hAdapter,
            pData->VidPnSourceId,
            pData->Width,
            pData->Height,
            pData->Format,
            pMethods,
            pData->MethodCount,
        };
     
        NTSTATUS ret = D3DKMTGetMultisampleMethodList(&list);
        
        if(BCRYPT_SUCCESS(ret))
        {
            for(int i = 0; i < pData->MethodCount; ++i)
            {
                pData->pMethodList[i].NumQualityLevels = pMethods[i].NumQualityLevels;
                pData->pMethodList[i].NumSamples = pMethods[i].NumSamples;
            }
        }
     
        delete [] pMethods;
        return (ret >= 0) ? S_OK : E_FAIL;
    }
     
    int main()
    {
        D3DKMT_UMDFILENAMEINFO kmInfo = 
        {
            KMTUMDVERSION_DX9,
            0
        };
     
        DISPLAY_DEVICE ddev;
        ddev.cb = sizeof(ddev);
        // Device Nummer 2 ist bei mir die Graphikkarte
        EnumDisplayDevices(NULL, 2, &ddev, 0);
     
        HDC hDc = CreateDC(NULL, ddev.DeviceName, NULL, NULL);
        // Fehlerbehandlung
     
        D3DKMT_OPENADAPTERFROMHDC openHdc = 
        {
            hDc,
            0,
            0,
            0
        };
     
        NTSTATUS status = D3DKMTOpenAdapterFromHdc(&openHdc);
        // Fehlerbehandlung
        DeleteDC(hDc);
     
        D3DKMT_QUERYADAPTERINFO info =
        {
            openHdc.hAdapter,
            KMTQAITYPE_UMDRIVERNAME,
            &kmInfo,
            sizeof(kmInfo)
        };
     
        status = D3DKMTQueryAdapterInfo(&info);
        // Fehlerbehandlung
        HMODULE hDriver = LoadLibraryW(kmInfo.UmdFileName);
        PFND3DDDI_OPENADAPTER pfnOpenAdapter = (PFND3DDDI_OPENADAPTER)GetProcAddress(hDriver, "OpenAdapter");
        // Fehlerbehandlung
     
        D3DDDI_ADAPTERCALLBACKS adapterCallbacks = 
        {
            QueryAdapterInfoCallback,
            GetMultisampleMethodListCallback
        };
     
        D3DDDI_ADAPTERFUNCS adapterFunctions = { 0 };
     
        D3DDDIARG_OPENADAPTER argOpenAdapter =
        {
            (HANDLE)openHdc.hAdapter,
            9,
            32,
            &adapterCallbacks,
            &adapterFunctions,
            0
        };
     
        HRESULT hRes = pfnOpenAdapter(&argOpenAdapter);
        // Fehlerbehandlung
    }

    Gruss
    Muepe
    Geändert von Muepe32 (16.04.11 um 09:21 Uhr)
     
    Viele Tutorials und Artikel zur Programmierung unter Windows mit C++ und C#. Tägliche Updates und Antworten auf eure Fragen:
    Win32Easy - Blog
    Es würde mich freuen, wenn ihr einen Kommentar postet!

  3. #3
    Technipion Technipion ist offline Mitglied
    Registriert seit
    Apr 2011
    Beiträge
    11
    Wow vielen Dank,
    du scheinst dich wirklich gut auszukennen...
    Ich guck mal ob ich das so in etwa hinkriege, sieht halt schon ziemlich aufwendig aus... aber danke für die step-by-step anleitung.
    Ich denke damit wären dann auch alle Fragen beantwortet.
     

  4. #4
    Avatar von Muepe32
    Muepe32 Muepe32 ist offline Mitglied Brokat
    Registriert seit
    Mar 2011
    Beiträge
    353
    Wenn du ganz auf die DirectX Runtime verzichten möchtest müsstest du dann auch teilweise die D3DKMTXxxxxx Funktionen selber implementieren, da diese manchmal nichts weiter machen als einen System Call in den DirectX Kernel Mode Treiber auszuführen. Da ich gerade schon bisschen mit dem WDK wieder bisschen rumgespielt hatte für den Code oben hat mich die Lust dazu bisschen gepackt und ich habe mal den Treiber geschrieben, der Teile der Funktionalitäten von D3DKMTQueryAdapterInfo bereit stellt (z.B. den UMD-Treiber abfragen). Wenn ich wieder zu Hause bin und die letzten kleinen Fehler aus dem Code entfernt habe kann ich dir das mal als Beispiel zeigen, vielleicht packt dich ja auch das Interesse daran
     
    Viele Tutorials und Artikel zur Programmierung unter Windows mit C++ und C#. Tägliche Updates und Antworten auf eure Fragen:
    Win32Easy - Blog
    Es würde mich freuen, wenn ihr einen Kommentar postet!

  5. #5
    Technipion Technipion ist offline Mitglied
    Registriert seit
    Apr 2011
    Beiträge
    11
    Ja also ich habe Interesse an dem Thema.
    Ich meine eine neue Grafikschnittstelle würde im Endeffekt eine Menge komfort mit sich bringen. Und wenn das möglich ist, wie du schon geschrieben hast, völlig auf die DirectX Runtime zu verzichten und trotzdem ne halbwegs gute Grafikausgabe hinzubekommen wäre natürlich fantastisch.
    Wenn du mir mal das Beispiel zeigen würdest... wäre ich dankbar für...
    ;-D
     

  6. #6
    Avatar von Muepe32
    Muepe32 Muepe32 ist offline Mitglied Brokat
    Registriert seit
    Mar 2011
    Beiträge
    353
    Eigentlich schreibt man ja die Treiber meistens in C, da die C++ Runtime wenn möglich nicht geladen werden kann/soll. Zudem lässt sich natürlich darüber streiten, ob der opake Zeiger, der bei DeviceIOControl für IOCTL_OPEN_ADAPTER zurückgegeben wird ideal ist, da er die Adresse des vom Treiber allozierten Speichers beinhält, aber vom Prinzip her sollte er zeigen, wohin es geht. Es ist klar, dass es sich beim Auslesen des UMD um eine einfache Aufgabe handelt und die Implementation von Funktionen wie D3DKMTPresent deutlich komplexer und schwerer wird schon alleine daher, weil praktisch 0 Dokumentation davon vorhanden ist.

    Der Hauptcode des Treibers sieht folgendermassen aus:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    
    #include "Common.h"
    #include "VideoDevice.h"
     
    DRIVER_DISPATCH UnsupportedFunction;
    DRIVER_DISPATCH IOControlFunction;
     
    NTSTATUS UnsupportedFunction(PDEVICE_OBJECT devObj, PIRP irp)
    {
        return STATUS_NOT_SUPPORTED;
    }
     
    __drv_dispatchType(IRP_MJ_DEVICE_CONTROL)
    NTSTATUS IOControlFunction(PDEVICE_OBJECT devObj, PIRP irp)
    {
        DbgPrint(__FUNCTION__);
        PIO_STACK_LOCATION loc = IoGetCurrentIrpStackLocation(irp);
        irp->IoStatus.Status = (NTSTATUS)0xC0000001;
        irp->IoStatus.Information = 0;
     
        if(loc == NULL)
        {
            IoCompleteRequest(irp, IO_NO_INCREMENT);
            return (NTSTATUS)0xC0000001;
        }
     
        if(!VideoDevice::IsValidIOCode(loc->Parameters.DeviceIoControl.IoControlCode))
        {
            IoCompleteRequest(irp, IO_NO_INCREMENT);
            return (NTSTATUS)0xC0000001;
        }
     
        ULONG numRet = 0;
     
        if(!VideoDevice::HandleIOControl(
            loc->Parameters.DeviceIoControl.IoControlCode,
            irp->AssociatedIrp.SystemBuffer,
            loc->Parameters.DeviceIoControl.InputBufferLength,
            irp->AssociatedIrp.SystemBuffer,
            loc->Parameters.DeviceIoControl.OutputBufferLength,
            &numRet
            ))
        {
            irp->IoStatus.Status = (NTSTATUS)0xC0000001;
            irp->IoStatus.Information = 0;
            IoCompleteRequest(irp, IO_NO_INCREMENT);
            return STATUS_UNSUCCESSFUL;
        }
        else
        {
            irp->IoStatus.Status = STATUS_SUCCESS;
            irp->IoStatus.Information = numRet;
            IoCompleteRequest(irp, IO_NO_INCREMENT);
            return STATUS_SUCCESS;
        }
    }
     
    DRIVER_UNLOAD UnloadDriver;
     
    void UnloadDriver(PDRIVER_OBJECT devObj)
    {
        UNICODE_STRING dosDeviceName;
        RtlInitUnicodeString(&dosDeviceName, L"\\DosDevices\\GraphicsAdapter"); 
     
        IoDeleteSymbolicLink(&dosDeviceName);
        IoDeleteDevice(devObj->DeviceObject);
    }
     
    extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
    {
        NTSTATUS NtStatus = STATUS_SUCCESS;
        unsigned int uiIndex = 0;
        PDEVICE_OBJECT pDeviceObject = NULL;
        UNICODE_STRING driverName, dosDeviceName;
     
        DbgPrint("Driver started => DriverEntry\n");
     
        RtlInitUnicodeString(&driverName, L"\\Device\\GraphicsAdapter");
        RtlInitUnicodeString(&dosDeviceName, L"\\DosDevices\\GraphicsAdapter"); 
     
        NtStatus = IoCreateDevice(pDriverObject, 0,
                                    &driverName, 
                                    FILE_DEVICE_UNKNOWN,
                                    FILE_DEVICE_SECURE_OPEN, 
                                    FALSE, &pDeviceObject);
     
        for(uiIndex = 0; uiIndex < IRP_MJ_MAXIMUM_FUNCTION; ++uiIndex)
            pDriverObject->MajorFunction[uiIndex] = UnsupportedFunction;
     
        pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOControlFunction;
        pDriverObject->DriverUnload = UnloadDriver;
     
        pDeviceObject->Flags |= DO_BUFFERED_IO;
        pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
     
        IoCreateSymbolicLink(&dosDeviceName, &driverName);
     
        return STATUS_SUCCESS;
    }

    Wie man sehen kann werden alle Aktionen aus dem User Mode über DeviceIOControl abgewickelt mit dem entsprechenden IOCTL-Code. VideoDevice::HandleIOControl wird nur aufgerufen für control codes, die METHOD_BUFFERED verwenden, dafür sorgt VideoDevice::IsValidIOControl. Daher können auch die Parameter immer gleich gewählt werden. Der Rest ist einfach Standard für die Treiberinitialisierung.

    Die Common.h beinhält dabei nur die entsprechenden statischen Includes:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    
    #pragma once
     
    #define _AMD64_
    #include <ntifs.h>
    #include <Ntstrsafe.h>
     
    typedef unsigned __int32 uint32;

    Wie du siehst ist mein Treiber für 64 Bit kompiliert (AMD64). Die VideoDevice.h beinhält die Definition der Klasse VideoDevice und die Control Codes (die alle Buffered I/O verwenden):
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    
    #pragma once
     
    enum VideoControlCodes
    {
        IOCTL_OPEN_ADAPTER          = CTL_CODE(FILE_DEVICE_UNKNOWN, 3000, METHOD_BUFFERED, FILE_ANY_ACCESS),
        IOCTL_GET_UMD_DRIVER_NAME   = CTL_CODE(FILE_DEVICE_UNKNOWN, 3001, METHOD_BUFFERED, FILE_ANY_ACCESS),
        IOCTL_CLOSE_ADAPTER         = CTL_CODE(FILE_DEVICE_UNKNOWN, 3002, METHOD_BUFFERED, FILE_ANY_ACCESS),
    };
     
    class VideoDevice
    {
        ULONG m_signature;
        UNICODE_STRING m_deviceName;
        PFILE_OBJECT m_fileObj;
        PDEVICE_OBJECT m_devObj, m_pdo;
        HANDLE m_hDrvReg;
        NTSTATUS m_lastActionStatus;
        bool OpenDevice();
        bool LoadPhysicalDevice();
     
        static bool HandleGetUMDName(PVOID in, ULONG inLen, PVOID out, ULONG outLen, PULONG bytesReturned);
        static bool HandleOpenAdapter(PVOID in, ULONG inLen, PVOID out, ULONG outLen, PULONG bytesReturned);
        static bool HandleCloseAdapter(PVOID in, ULONG inLen, PVOID out, ULONG outLen, PULONG bytesReturned);
    public:
        bool Constructor(uint32 num);
        void Destructor();
     
        bool LoadDriverRegistry();
        bool QueryDriverRegistryKey(WCHAR* keyName, PUNICODE_STRING dstValue);
        NTSTATUS GetLastStatus() { return m_lastActionStatus; }
        void SetLastStatus(NTSTATUS status) { m_lastActionStatus = status; }
     
        static bool HandleIOControl(ULONG ioCode, PVOID inBuffer, ULONG inLen, PVOID outBuffer, ULONG outLen, PULONG bytesReturned);
        static bool IsValidIOCode(ULONG ioCode);
    };

    Der relevante Code ist dann in der VideoDevice.cpp, da hab ich auch bisschen Kommentare eingefügt, was die Funktionen machen:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    
    #include "Common.h"
    #include "VideoDevice.h"
     
    // Ist ein Ersatz für den richtigen Konstruktor VideoDevice::VideoDevice, der nie aufgerufen
    // wird, da wir keine C++-Runtime haben und daher der bekannte operator new schlicht nicht
    // existiert, der dann den Konstruktor normalerweise aufruft. Ist aber nicht weiter tragisch
    // da dieser ja auch nur eine simple Funktion ist wie diese hier.
    bool VideoDevice::Constructor(uint32 id)
    {
        DbgPrint(__FUNCTION__);
        m_signature = 'VDDV';
        m_pdo = NULL;
        m_devObj = NULL;
        m_fileObj = NULL;
        m_hDrvReg = NULL;
        m_lastActionStatus = STATUS_SUCCESS;
        WCHAR devString[50] = { 0 };
        RtlStringCchPrintfW(devString, 50, L"\\Device\\Video%u", id);
        RtlInitUnicodeString(&m_deviceName, devString);
        return OpenDevice();
    }
     
    // Siehe Kommentar von VideoDevice::Constructur. Gilt auch hier, da delete fehlt
    void VideoDevice::Destructor()
    {
        DbgPrint(__FUNCTION__);
        if(m_fileObj != NULL)
            ObDereferenceObject(m_fileObj);
    }
     
    // Versucht einen Zeiger auf das entsprechende Videodevice zu erhalten mit Read access.
    // Falls das möglich war wird das physikalische Device Object (PDO) gesucht, dass wir
    // für alle späteren Funktionen brauchen.
    bool VideoDevice::OpenDevice()
    {
        DbgPrint(__FUNCTION__);
        NTSTATUS status = IoGetDeviceObjectPointer(&m_deviceName, FILE_READ_DATA, &m_fileObj, &m_devObj);
        if(NT_SUCCESS(status) == FALSE)
        {
            SetLastStatus(status);
            return false;
        }
     
        return LoadPhysicalDevice();
    }
     
    // Sucht das PDO mit der major function IRP_MJ_PNP und der minor function
    // IRP_MN_QUERY_DEVICE_RELATIONS. Wenn das Video device dies nicht unterstützt
    // funktioniert das ganze entsprechend nicht.
    bool VideoDevice::LoadPhysicalDevice()
    {
        DbgPrint(__FUNCTION__);
        KEVENT hEvent;
        IO_STATUS_BLOCK ioStatus;
        KeInitializeEvent(&hEvent, NotificationEvent, FALSE);
        PIRP irp = IoBuildSynchronousFsdRequest(
            IRP_MJ_PNP,
            m_devObj,
            NULL,
            0,
            NULL,
            &hEvent,
            &ioStatus
        );
     
        if(irp == NULL)
        {
            SetLastStatus(STATUS_DATA_ERROR);
            return false;
        }
     
        PIO_STACK_LOCATION irpLoc;
        irpLoc = IoGetNextIrpStackLocation(irp);
        irpLoc->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
        irpLoc->MajorFunction = IRP_MJ_PNP;
        irpLoc->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
        irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
     
        NTSTATUS stat = IofCallDriver(m_devObj, irp);
        if(stat == STATUS_PENDING)
        {
            KeWaitForSingleObject(&hEvent, Executive, KernelMode, FALSE, NULL);
            stat = ioStatus.Status;
        }
     
        if(NT_SUCCESS(stat) == FALSE)
        {
            SetLastStatus(stat);
            return false;
        }
     
        PDEVICE_RELATIONS rel = (PDEVICE_RELATIONS)ioStatus.Information;
        if(rel == NULL || rel->Count == 0)
        {
            SetLastStatus(STATUS_DATA_ERROR);
            return false;
        }
     
        m_pdo = rel->Objects[0];
        ExFreePool(rel);
        SetLastStatus(STATUS_SUCCESS);
        return true;
    }
     
    // Jeder Treiber für jedes Device für das er verwendet wird kann einen Pfad in der 
    // Registry haben in dem er seine Daten speichert. Dies ist in der Regel dann in
    // HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Video\{TreiberGUID}\DeviceID\
    // IoOpenDeviceRegistryKey gibt einen HANDLE zurück, der den entsprechenden Pfad 
    // geöffnet hat.
    bool VideoDevice::LoadDriverRegistry()
    {
        DbgPrint(__FUNCTION__);
        if(m_hDrvReg != NULL)
            ZwClose(m_hDrvReg);
     
        m_hDrvReg = NULL;
        NTSTATUS status = IoOpenDeviceRegistryKey(m_pdo, PLUGPLAY_REGKEY_DRIVER, KEY_READ, &m_hDrvReg);
        SetLastStatus(status);
        return NT_SUCCESS(status);
    }
     
    // Versucht einen __STRING__ Wert aus dem Registryset des Devicetreibers zu laden.
    bool VideoDevice::QueryDriverRegistryKey(WCHAR* keyName, PUNICODE_STRING dstString)
    {
        DbgPrint(__FUNCTION__);
        if(m_hDrvReg == NULL || dstString == NULL || keyName == NULL)
        {
            SetLastStatus(STATUS_INVALID_PARAMETER);
            return false;
        }
     
        UNICODE_STRING keyString;
        RtlInitUnicodeString(&keyString, keyName);
     
        ULONG fullLen = 0;
        NTSTATUS status = ZwQueryValueKey(m_hDrvReg, &keyString, KeyValuePartialInformation, NULL, 0, &fullLen);
        if((status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL) || fullLen == 0)
        {
            SetLastStatus(status);
            return false;
        }
     
        PKEY_VALUE_PARTIAL_INFORMATION vpi = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, fullLen, 'VDDC');
        if(vpi == NULL)
        {
            SetLastStatus(STATUS_NO_MEMORY);
            return false;
        }
     
        status = ZwQueryValueKey(m_hDrvReg, &keyString, KeyValuePartialInformation, vpi, fullLen, &fullLen);
        if(NT_SUCCESS(status) == false || vpi->DataLength == 0)
        {
            SetLastStatus(status);
            ExFreePool(vpi);
            return false;
        }
     
        if(vpi->Type != REG_SZ && vpi->Type != REG_MULTI_SZ && vpi->Type != REG_EXPAND_SZ)
        {
            SetLastStatus(STATUS_DATA_ERROR);
            ExFreePool(vpi);
            return false;
        }
     
        RtlInitUnicodeString(&keyString, (WCHAR*)vpi->Data);
        dstString->Length = (vpi->DataLength - sizeof(WCHAR)) / sizeof(WCHAR);
        dstString->MaximumLength = dstString->Length + 1;
        dstString->Buffer = (PWCHAR)ExAllocatePoolWithTag(NonPagedPool, dstString->MaximumLength * sizeof(WCHAR), 'VDDC');
        RtlCopyUnicodeString(dstString, &keyString);
        ExFreePool(vpi);
        SetLastStatus(status);
        return true;
    }
     
    // Ruft eine für den I/O-Control passende Funktion auf
    bool VideoDevice::HandleIOControl(ULONG ioCode, PVOID inBuffer, ULONG inLen, PVOID outBuffer, ULONG outLen, PULONG bytesReturned)
    {
        DbgPrint(__FUNCTION__);
        switch(ioCode)
        {
        case IOCTL_GET_UMD_DRIVER_NAME:
            {
                return VideoDevice::HandleGetUMDName(inBuffer, inLen, outBuffer, outLen, bytesReturned);
            }
     
        case IOCTL_OPEN_ADAPTER:
            {
                return VideoDevice::HandleOpenAdapter(inBuffer, inLen, outBuffer, outLen, bytesReturned);
            }
     
        case IOCTL_CLOSE_ADAPTER:
            {
                return VideoDevice::HandleCloseAdapter(inBuffer, inLen, outBuffer, outLen, bytesReturned);
            }
     
        default:
            return false;
        }
    }
     
    bool VideoDevice::IsValidIOCode(ULONG code)
    {
        return (code == IOCTL_GET_UMD_DRIVER_NAME || code == IOCTL_OPEN_ADAPTER || code == IOCTL_CLOSE_ADAPTER);
    }
     
    bool VideoDevice::HandleCloseAdapter(PVOID in, ULONG inLen, PVOID out, ULONG outLen, PULONG bytesReturned)
    {
        DbgPrint(__FUNCTION__);
        *bytesReturned = 0;
        if(inLen < sizeof(HANDLE*) || in == NULL)
            return false;
     
        VideoDevice* dev = *(VideoDevice**)in;
        if(dev->m_signature != 'VDDV')
            return false;
     
        dev->Destructor();
        ExFreePool(dev);
        return true;
    }
     
    bool VideoDevice::HandleOpenAdapter(PVOID in, ULONG inLen, PVOID out, ULONG outLen, PULONG bytesReturned)
    {
        DbgPrint(__FUNCTION__);
        *bytesReturned = 0;
        if(outLen < sizeof(HANDLE) || out == NULL)
            return false;
     
        VideoDevice* retValue = (VideoDevice*)ExAllocatePoolWithTag(NonPagedPool, sizeof(VideoDevice), 'VDDC');
        if(retValue == NULL)
        {
            *(HANDLE*)out = NULL;
            return false;
        }
     
        if(!retValue->Constructor(6))
        {
            *(HANDLE*)out = NULL;
            ExFreePool(retValue);
            return true;
        }
     
        *(HANDLE*)out = (HANDLE)retValue;
        *bytesReturned = sizeof(HANDLE);
        return true;
    }
     
    bool VideoDevice::HandleGetUMDName(PVOID in, ULONG inLen, PVOID out, ULONG outLen, PULONG bytesReturned)
    {
        DbgPrint(__FUNCTION__);
        *bytesReturned = 0;
        if(inLen < sizeof(HANDLE*) || in == NULL || out == NULL || outLen == 0)
            return false;
     
        VideoDevice* dev = *(VideoDevice**)in;
        if(dev->m_signature != 'VDDV')
            return false;
     
        if(!dev->LoadDriverRegistry())
            return false;
     
        UNICODE_STRING strDriver;
        if(!dev->QueryDriverRegistryKey(L"UserModeDriverNameWoW", &strDriver))
            return false;
     
        RtlStringCchCopyNW((PWSTR)out, outLen, strDriver.Buffer, strDriver.MaximumLength);
        ExFreePool(strDriver.Buffer);
     
        *bytesReturned = outLen;
        return true;
    }

    Eine Usermode Applikation kann dann den Treiber folgendermassen verwendet (nachdem er installiert wurde):
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
    #include <windows.h>
    #include <iostream>
     
    enum VideoControlCodes
    {
        IOCTL_OPEN_ADAPTER          = CTL_CODE(FILE_DEVICE_UNKNOWN, 3000, METHOD_BUFFERED, FILE_ANY_ACCESS),
        IOCTL_GET_UMD_DRIVER_NAME   = CTL_CODE(FILE_DEVICE_UNKNOWN, 3001, METHOD_BUFFERED, FILE_ANY_ACCESS),
        IOCTL_CLOSE_ADAPTER         = CTL_CODE(FILE_DEVICE_UNKNOWN, 3002, METHOD_BUFFERED, FILE_ANY_ACCESS),
    };
     
    int main(void)
    {
        HANDLE hFile = CreateFile("\\\\.\\GraphicsAdapter", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
        if(hFile != INVALID_HANDLE_VALUE)
        {
            HANDLE hAdapter = 0;
            DWORD bytesRet = 0;
            DeviceIoControl(hFile, IOCTL_OPEN_ADAPTER, NULL, 0, &hAdapter, sizeof(HANDLE*), &bytesRet, NULL);
            if(hAdapter != NULL)
            {
                WCHAR strUmd[MAX_PATH];
                BOOL ret = DeviceIoControl(hFile, IOCTL_GET_UMD_DRIVER_NAME, &hAdapter, sizeof(HANDLE*), strUmd, MAX_PATH, &bytesRet, NULL);
                if(ret == FALSE)
                    std::cout << "Unable to get the user mode driver!" << std::endl;
                else
                    std::wcout << L"UserModeDriver: " << strUmd << std::endl;
            }
     
            DeviceIoControl(hFile, IOCTL_CLOSE_ADAPTER, &hAdapter, sizeof(HANDLE*), NULL, 0, &bytesRet, NULL);
        }
        CloseHandle(hFile);
        std::cin.get();
    }

    Ein Anfang, und es stünde noch seeeehr viel vor dir um einen eigenen Treiber für den Part zu schreiben, den der Treiber nicht selber macht. Ein Teil der folgenden Funktionen müsstest du selber implementieren (wenn du richtig motiviert bist und drin bist gehen ja auch alle, wobei das dann redundant wäre, da sie schon im Treiber win32k.sys definiert sind). http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx

    Gruss
    Muepe
    Geändert von Muepe32 (18.04.11 um 23:14 Uhr)
    Technipion bedankt sich. 
    Viele Tutorials und Artikel zur Programmierung unter Windows mit C++ und C#. Tägliche Updates und Antworten auf eure Fragen:
    Win32Easy - Blog
    Es würde mich freuen, wenn ihr einen Kommentar postet!

Ähnliche Themen

  1. Eigene TagLib schreiben
    Von robgeb im Forum Enterprise Java (JEE, J2EE, Spring & Co.)
    Antworten: 5
    Letzter Beitrag: 01.09.09, 07:20
  2. Antworten: 7
    Letzter Beitrag: 12.03.09, 09:26
  3. Serielle Schnittstelle auslesen
    Von Ragnarok83 im Forum C/C++
    Antworten: 2
    Letzter Beitrag: 14.10.08, 21:08
  4. Mit PHP in eigene Logfiles schreiben
    Von SaschaT im Forum PHP
    Antworten: 8
    Letzter Beitrag: 08.04.08, 00:14
  5. MPI-Schnittstelle mit Java auslesen?
    Von king_nereos im Forum Java
    Antworten: 0
    Letzter Beitrag: 09.03.04, 15:56

Stichworte