1Danke
ERLEDIGT
JA
JA
ANTWORTEN
5
5
ZUGRIFFE
726
726
EMPFEHLEN
-
15.04.11 23:41 #1
- 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.
-
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
MuepeGeä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!
-
16.04.11 12:04 #3
- 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.
-
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!
-
18.04.11 17:31 #5
- 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
-
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
MuepeGeändert von Muepe32 (18.04.11 um 23:14 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!
Ähnliche Themen
-
Eigene TagLib schreiben
Von robgeb im Forum Enterprise Java (JEE, J2EE, Spring & Co.)Antworten: 5Letzter Beitrag: 01.09.09, 07:20 -
Eigene API / Schnittstelle zwischen zwei Servern
Von String im Forum PHPAntworten: 7Letzter Beitrag: 12.03.09, 09:26 -
Serielle Schnittstelle auslesen
Von Ragnarok83 im Forum C/C++Antworten: 2Letzter Beitrag: 14.10.08, 21:08 -
Mit PHP in eigene Logfiles schreiben
Von SaschaT im Forum PHPAntworten: 8Letzter Beitrag: 08.04.08, 00:14 -
MPI-Schnittstelle mit Java auslesen?
Von king_nereos im Forum JavaAntworten: 0Letzter Beitrag: 09.03.04, 15:56





Zitieren
Login






