{"id":187,"date":"2007-08-29T10:04:55","date_gmt":"2007-08-29T10:04:55","guid":{"rendered":"https:\/\/driverentry.com.br\/en\/2007\/08\/29\/using-fileobject-and-fscontext\/"},"modified":"2026-07-27T20:44:45","modified_gmt":"2026-07-27T20:44:45","slug":"using-fileobject-and-fscontext","status":"publish","type":"post","link":"https:\/\/driverentry.com.br\/en\/2007\/08\/29\/using-fileobject-and-fscontext\/","title":{"rendered":"Using FileObject and FsContext"},"content":{"rendered":"<div style=\"text-align: right;\"><a href=\"https:\/\/driverentry.com.br\/2007\/08\/29\/usando-fileobject-e-fscontext\/\"><img loading=\"lazy\" decoding=\"async\" title=\"Em Portugu\u00eas\" src=\"https:\/\/driverentry.com.br\/en\/wp-content\/uploads\/2026\/07\/br.gif\" alt=\"\" width=\"21\" height=\"19\" \/><\/a><\/div>\n<p>Well, with some posts and a little patience to endure my jokes, we can construct a simple driver that responds to calls from applications. A call to <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa363858(VS.85).aspx\">CreateFile<\/a> function creates a connection between the application and device, returning a handle which will later be used to route reading\/writting requests to the device. If there are more calls to <em>CreateFile<\/em> function, new handles will be returned. Like it happens with files, each handle has its own context. Suppose you open the same file twice so, you will get two handles with different contexts. A reading of 100 bytes from the first handle would cause the file&#8217;s current location be different from the initial position. A new reading using the same handle would result on getting the next 100 bytes ahead of the ones already read. Now if you used the second handle, you would get the first 100 bytes of the file. That&#8217;s because each handle would keep different file locations. In this post, I will talk about how to keep this context between the different opened handles for your device.<\/p>\n<h3>The issue in practice<\/h3>\n<p>Not long ago, <a href=\"https:\/\/driverentry.com.br\/en\/2007\/06\/18\/we-want-samples\/\">in one of my posts<\/a>, I gave a basic driver example that implements a linked list of <em>buffers<\/em> that were written to the device. The same <em>buffers<\/em> are obtained from further reads to the same device. This post will be based on this sample driver to make the tests and suggested modifications. The driver&#8217;s string list was implemented as a single global variable. If there is a single list, the various handles gotten from the applications will manipulate this same list.<\/p>\n<p>Remember that the test program writes the strings, that were typed in a console at the device until an empty one is supplied. When this occurs, the application starts reading and displaying the results at the screen. Thus, the same provided string sequence should be displayed. To reproduce the problem, follow the steps below with the test driver already installed:<\/p>\n<ol>\n<li>Open up a <em>Prompt<\/em> window and execute a test program instance.<\/li>\n<li>Enter the string sequence that goes from &#8220;111&#8221;, &#8220;222&#8221; until &#8220;555&#8221;, but don&#8217;t enter the empty one yet.<\/li>\n<li>Open up a new <em>Prompt<\/em> window and execute another test program instance.<\/li>\n<li>On this new window, enter the string sequence that goes from &#8220;666&#8221; until &#8220;999&#8221; and then, an empty one.<\/li>\n<li>Go back to the previous instance and then, enter an empty string into the test program.<\/li>\n<\/ol>\n<p>You should get an output as it is shown below. Note that the first test program instance has not read any string, despite having written several ones. These missing strings were got to the second test program instance.<\/p>\n<div style=\"text-align: center;\"><img decoding=\"async\" src=\"https:\/\/driverentry.com.br\/en\/wp-content\/uploads\/2026\/07\/OldEchoTest.png\" alt=\"\" \/><\/div>\n<h3>Separating lists<\/h3>\n<p>Creating an algorithm able to separate these lists using the process identification could even work, but try to imagine that a single application could use two different libraries, which in turn, would use these lists. In this way, one library list would merge into the other library list, since both libraries are at the same process. To separate the context using various device openings, we use the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ff545834(VS.85).aspx\">FileObject<\/a> member of the <em>current stack location<\/em>.<\/p>\n<p>When an application calls the <em>CreateFile<\/em> function, this request goes to the <em>ObjectManager<\/em> which verifies the existence of the desired object, then checks whether the application has rights to obtain a handle to this object, and, if everything is agreed, the request reaches your driver in the form of an <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ff550694(VS.85).aspx\">IRP<\/a> with its <em>Major Function<\/em> as <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ff550729(VS.85).aspx\">IRP_MJ_CREATE<\/a>. To get the <em>FileObject<\/em> referring to this new connection being created, you need to do as shown at the code below.<\/p>\n<div style=\"font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;\">\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Gets the FileObject referring to this list<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    pStack = IoGetCurrentIrpStackLocation(pIrp);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    pFileObject = pStack-&gt;FileObject;<\/pre>\n<\/div>\n<h3>This or that list?<\/h3>\n<p>All subsequent operations that come from the same object instance will come with the same <em>FileObject<\/em>. This helps tracking the context of a certain device opening from the several ones that your driver receives.<\/p>\n<p><strong>So, all that I need to do is to create a list of <em>FileObjects<\/em> and then link each one of them to a string list?<\/strong> The idea of linking the <em>FileObject<\/em> to a structure that holds this context is so obvious that the system has already reserved a space into the <strong>FILE_OBJECT<\/strong> structure exclusively for this use.<\/p>\n<div style=\"font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;\">\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: blue;\">typedef<\/span> <span style=\"color: blue;\">struct<\/span> _FILE_OBJECT<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">{<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    CSHORT  Type;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    CSHORT  Size;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    PDEVICE_OBJECT  DeviceObject;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    PVPB  Vpb;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA; color: red;\">    PVOID  FsContext;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF; color: red;\">    PVOID  FsContext2;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    PSECTION_OBJECT_POINTERS  SectionObjectPointer;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    PVOID  PrivateCacheMap;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    NTSTATUS  FinalStatus;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">struct<\/span> _FILE_OBJECT  *RelatedFileObject;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    BOOLEAN  LockOperation;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    BOOLEAN  DeletePending;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    BOOLEAN  ReadAccess;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    BOOLEAN  WriteAccess;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    BOOLEAN  DeleteAccess;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    BOOLEAN  SharedRead;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    BOOLEAN  SharedWrite;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    BOOLEAN  SharedDelete;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    ULONG  Flags;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    UNICODE_STRING  FileName;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    LARGE_INTEGER  CurrentByteOffset;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    ULONG  Waiters;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    ULONG  Busy;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    PVOID  LastLock;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    KEVENT  Lock;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    KEVENT  Event;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    PIO_COMPLETION_CONTEXT  CompletionContext;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    KSPIN_LOCK  IrpListLock;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    LIST_ENTRY  IrpList;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    PVOID  FileObjectExtension;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">} FILE_OBJECT, *PFILE_OBJECT;<\/pre>\n<\/div>\n<p>The <em>FsContext<\/em> and <em>FsContext2<\/em> fields are used for this purpose and unless you implement a filter, you can at ease use them. To make each device opening has its own list, it is necessary to store the head list address in one of these fields, as it is shown below at the new implementation of <em>OnCreate<\/em>. The whole source code changes are available for downloading at the end of this post.<\/p>\n<div style=\"font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;\">\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">\/****<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">***     OnCreate<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">**      This routine is called whenever an application or driver<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**      tries to get a handle to the device we have created.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">*\/<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">NTSTATUS<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">OnCreate(IN PDEVICE_OBJECT  pDeviceObj,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">         IN PIRP            pIrp)<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">{<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    NTSTATUS            nts = STATUS_SUCCESS;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    PBUFFER_LIST_HEAD   pListHead;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    PIO_STACK_LOCATION  pStack;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; A hello to the debugger...<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    KdPrint((<span style=\"color: #a31515;\">\"Opening EchoDevice...\\n\"<\/span>));<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Allocates the list head for this IRP_MJ_CREATE<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    pListHead = (PBUFFER_LIST_HEAD) ExAllocatePoolWithTag(<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        PagedPool,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: blue;\">sizeof<\/span>(BUFFER_LIST_HEAD),<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        ECHO_TAG);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: blue;\">if<\/span> (pListHead)<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    {<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/-f--&gt; Initializing the buffer list and its Mutex<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        InitializeListHead(&amp;pListHead-&gt;BufferList);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        KeInitializeMutex(&amp;pListHead-&gt;Mutex, <span style=\"color: purple;\">0<\/span>);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/-f--&gt; We store the context to the FileObject.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        pStack = IoGetCurrentIrpStackLocation(pIrp);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        pStack-&gt;FileObject-&gt;FsContext = pListHead;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    }<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: blue;\">else<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        nts = STATUS_INSUFFICIENT_RESOURCES;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Here we complete the IRP with success.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    pIrp-&gt;IoStatus.Status = nts;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    pIrp-&gt;IoStatus.Information = <span style=\"color: purple;\">0<\/span>;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    IoCompleteRequest(pIrp, IO_NO_INCREMENT);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">return<\/span> nts;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">}<\/pre>\n<\/div>\n<h3>Is a FileObject equivalent to a Handle?<\/h3>\n<p>No. Initially we have a handle for each <em>FileObject<\/em>, but the number of handles to a <em>FileObject<\/em> increases as their handles are duplicated. When the <em>CreateFile <\/em>function is called, your driver receives an <strong>IRP_MJ_CREATE<\/strong>; however your driver is not alerted when someone calls the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms724251(VS.85).aspx\">DuplicateHandle<\/a> function. Thus, each handle points to an object but an object can be pointed out by several handles.<\/p>\n<h3>Who will clean this mess?<\/h3>\n<p>When all references to a given <em>FileObject<\/em> are released, your device will receive an <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ff550720(VS.85).aspx\">IRP_MJ_CLOSE<\/a>. Let&#8217;s use this event to clean up any remaining strings on the list.<\/p>\n<div style=\"font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;\">\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">\/****<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">***     OnClose<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">**      I'll make it simple just saying that this routine is called, whenever<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**      an application or driver closes the handle which was previously opened.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">**      Actually, this does not happen exactly in this way. (postponed to a future post)<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">*\/<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">NTSTATUS<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">OnClose(IN PDEVICE_OBJECT  pDeviceObj,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        IN PIRP            pIrp)<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">{<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    PBUFFER_LIST_HEAD   pListHead;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    PIO_STACK_LOCATION  pStack;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    PLIST_ENTRY         pEntry;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    PBUFFER_ENTRY       pBufferEntry;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; A hello to the debugger...<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    KdPrint((<span style=\"color: #a31515;\">\"Closing EchoDevice...\\n\"<\/span>));<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Retrieves the list referring to this FileObject.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    pStack = IoGetCurrentIrpStackLocation(pIrp);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    pListHead = (PBUFFER_LIST_HEAD)pStack-&gt;FileObject-&gt;FsContext;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Here, we remove all the remaining nodes that were not read<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      by the application. That would happen if the application had called<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      WriteFile but not ReadFile.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">while<\/span>(!IsListEmpty(&amp;pListHead-&gt;BufferList))<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    {<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/-f--&gt; It takes the first node from the list.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        pEntry = RemoveHeadList(&amp;pListHead-&gt;BufferList);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/-f--&gt; Retrieves the base address from the node<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        pBufferEntry = CONTAINING_RECORD(pEntry, BUFFER_ENTRY, Entry);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/-f--&gt; Finally releases the memory used by<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/      that node.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        ExFreePool(pBufferEntry);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    }<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Releases the memory used by the head list.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    ExFreePool(pListHead);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">&nbsp;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Here, we complete the IRP with success.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    pIrp-&gt;IoStatus.Status = STATUS_SUCCESS;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    pIrp-&gt;IoStatus.Information = <span style=\"color: purple;\">0<\/span>;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    IoCompleteRequest(pIrp, IO_NO_INCREMENT);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">return<\/span> STATUS_SUCCESS;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">}<\/pre>\n<\/div>\n<p>When an application is terminated or even when it falls unwillingly, all those application handles are closed by the system. Thus, it is guaranteed that your driver will always receive the <strong>IRP_MJ_CLOSE<\/strong> related to the object that was released. Actually, there is a little story about <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ff550718(VS.85).aspx\">IRP_MJ_CLEANUP<\/a> and <strong>IRP_MJ_CLOSE<\/strong> that we will let to the next time.<\/p>\n<p>Once implemented the change, each opened handle will own list, unless the handle is duplicated. If we repeat the same sequence of the listed steps above to force the error, we will get the following output.<\/p>\n<div style=\"text-align: center;\"><img decoding=\"async\" src=\"https:\/\/driverentry.com.br\/en\/wp-content\/uploads\/2026\/07\/NewEchoTest.png\" alt=\"\" \/><\/div>\n<p>In a future post, I&#8217;ll show you how to give names to the lists in order to allow different processes begin able to open the same list from a known name.<\/p>\n<p>CYA! \ud83d\ude42<\/p>\n<p class=\"download\"><a href=\"http:\/\/www.driverentry.com.br\/samples\/FileObjEcho.zip\">FileObjEcho.zip<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Well, with some posts and a little patience to endure my jokes, we can construct a simple driver that responds to calls from applications. A call to CreateFile function creates a connection between the application and device, returning a handle which will later be used to route reading\/writting requests to the device. If there are [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"pagelayer_contact_templates":[],"_pagelayer_content":"","footnotes":""},"categories":[1],"tags":[],"class_list":["post-187","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/posts\/187","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/comments?post=187"}],"version-history":[{"count":3,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/posts\/187\/revisions"}],"predecessor-version":[{"id":302,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/posts\/187\/revisions\/302"}],"wp:attachment":[{"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/media?parent=187"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/categories?post=187"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/tags?post=187"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}