{"id":370,"date":"2008-10-16T11:07:59","date_gmt":"2008-10-16T11:07:59","guid":{"rendered":"https:\/\/driverentry.com.br\/en\/2008\/10\/16\/buffered-direct-or-neither-in-ioctls\/"},"modified":"2026-07-29T19:23:35","modified_gmt":"2026-07-29T19:23:35","slug":"buffered-direct-or-neither-in-ioctls","status":"publish","type":"post","link":"https:\/\/driverentry.com.br\/en\/2008\/10\/16\/buffered-direct-or-neither-in-ioctls\/","title":{"rendered":"Buffered, Direct or Neither in IOCTLs"},"content":{"rendered":"<div style=\"text-align: right;\"><a href=\"https:\/\/driverentry.com.br\/2008\/10\/16\/buffered-direct-ou-neither-em-ioctls\/\"><img loading=\"lazy\" decoding=\"async\" title=\"Em Portugues\" src=\"https:\/\/driverentry.com.br\/en\/wp-content\/uploads\/2026\/07\/br.gif\" alt=\"\" width=\"21\" height=\"19\" \/><\/a><\/div>\n<p>After <a href=\"https:\/\/driverentry.com.br\/en\/2008\/09\/11\/a-pinch-of-virtual-memory\/\">a pinch of virtual memory<\/a> to understand the most relevant concepts and take a good stroll through the <a href=\"https:\/\/driverentry.com.br\/en\/2008\/10\/01\/buffered-direct-or-neither\/\">data-transfer methods<\/a> between application and driver, today we are going to close this trilogy talking about the data-transfer methods in IOCTLs. If you do not know how to create or use IOCTLs, this <a href=\"https:\/\/driverentry.com.br\/en\/2008\/06\/07\/creating-and-using-ioctls\/\">other post<\/a> may help.<\/p>\n<h3>Flags do not help here<\/h3>\n<p>In the post about the data-transfer methods it was seen that we define the transfer method through a bit mask located in the <strong>Flags<\/strong> field in a <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa491677.aspx\">DEVICE_OBJECT<\/a>. The method chosen here defines how the I\/O Manager will handle the data in the driver&#8217;s read (<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms806158.aspx\">IRP_MJ_READ<\/a>) and write (<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms806163.aspx\">IRP_MJ_WRITE<\/a>) operations. The chosen method is applied to both operations. We cannot have writes using one method while reads are performed using another. In the case of IOCTLs, the story is different. The transfer method is chosen when you define the <strong>control code<\/strong> using the <strong>CTL_CODE<\/strong> macro.<\/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: #FFFFFF;\"><span style=\"color: blue;\">#define<\/span> IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)<\/pre>\n<\/div>\n<p>For a more detailed explanation about the use of this macro, visit <a href=\"https:\/\/driverentry.com.br\/en\/2008\/06\/07\/creating-and-using-ioctls\/\">this post<\/a>, or take a look at the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms795909.aspx\">reference<\/a>. Here I will only comment on the data-transfer methods, which is selected by the <strong>Method<\/strong> parameter of this macro. The use of this macro to define IOCTLs is normally done in a header file that will be shared between the application and the driver. The definition of this macro is obtained from the <strong>Windows.h<\/strong> header for <em>User-Mode<\/em> and <strong>Ntddk.h<\/strong> for <em>Kernel-Mode<\/em>. Below is the definition of the IOCTLs we will implement in 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;\">\/\/-f--&gt; Here we define the copy IOCTLs using the<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">\/\/      different data-transfer methods between<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">\/\/      application and driver.<\/span><\/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; Using system copy<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: blue;\">#define<\/span> IOCTL_COPY_BUFFERED CTL_CODE(FILE_DEVICE_UNKNOWN,   \\<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                                     <span style=\"color: purple;\">0x800<\/span>,                 \\<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                                     METHOD_BUFFERED,       \\<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                                     FILE_ANY_ACCESS)<\/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; Locking the application pages<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: blue;\">#define<\/span> IOCTL_COPY_DIRECT   CTL_CODE(FILE_DEVICE_UNKNOWN,   \\<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                                     <span style=\"color: purple;\">0x801<\/span>,                 \\<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                                     METHOD_OUT_DIRECT,     \\<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                                     FILE_ANY_ACCESS)<\/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; Come what may<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: blue;\">#define<\/span> IOCTL_COPY_NEITHER  CTL_CODE(FILE_DEVICE_UNKNOWN,   \\<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                                     <span style=\"color: purple;\">0x802<\/span>,                 \\<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                                     METHOD_NEITHER,        \\<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                                     FILE_ANY_ACCESS)<\/pre>\n<\/div>\n<p>As you can observe, we can have different data-transfer methods for different IOCTLs. In this post I will create a driver that offers three IOCTLs that simply copy the data received in the input buffer to the output buffer. What we will have to do initially is use the CTL_CODE macro to create the IOCTLs for the services that our example driver will offer. The complete code of the example driver is available for download at the end of this post.<\/p>\n<p><strong>Come on, Fernando, I included <em>Windows.h<\/em> in my test application, but the definition of the CTL_CODE macro is still missing and I get the error message below. Am I using an incomplete <em>Windows.h<\/em>?<\/strong><\/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: #FFFFFF;\">Z:\\sources\\testapp.cpp(45) : error C3861: 'CTL_CODE': identifier not found<\/pre>\n<\/div>\n<p>The thing is this: The Wizard of the more recent versions of Visual Studio creates the <em>StdAfx.h<\/em> file containing, among others, the following lines:<\/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;\">#define<\/span> WIN32_LEAN_AND_MEAN             <span style=\"color: green;\">\/\/ Exclude rarely-used stuff from Windows headers<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">\/\/ Windows Header Files:<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: blue;\">#include<\/span><\/pre>\n<\/div>\n<p><img decoding=\"async\" style=\"float: right; margin: 0px 10px;\" src=\"https:\/\/driverentry.com.br\/en\/wp-content\/uploads\/2026\/07\/Lemming.png\" alt=\"\" border=\"0\" \/><\/p>\n<p>Notice that the <strong>WIN32_LEAN_AND_MEAN<\/strong> symbol is defined before the inclusion of the <em>Windows.h<\/em> file. In order to gain compilation speed, this symbol avoids the declaration of some tons of definitions that are rarely used by applications. What is happening is that the CTL_CODE macro is one of these rarely used things. Yep, man, interacting with drivers is not for just anyone. Anyway, to solve this problem you just comment out the definition of this symbol and everyone will live happily ever after.<\/p>\n<p><strong>Hold on there, Fernando! Everyone except me, who did not use the Visual Studio Wizard. I am using the SOURCES file to compile my application. The fact is that in my source there is no definition of that so-called &#8220;Win32 <a href=\"http:\/\/en.wikipedia.org\/wiki\/Lemmings_(video_game)\">Lemming<\/a>&#8220;. What is the little excuse now?<\/strong><\/p>\n<p>If you are using the SOURCES file to compile your test application, just as I am doing in this post&#8217;s example, you will need to add the highlighted line below so that the WIN32_LEAN_AND_MEAN symbol is not defined by the WDK&#8217;s default makefile.<\/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;\">TARGETNAME=TestApp<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">TARGETTYPE=PROGRAM<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">USE_LIBCMT=1<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">UMTYPE=console<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA; color: red;\">NOT_LEAN_AND_MEAN=1<\/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;\">SOURCES=TestApp.cpp<\/pre>\n<\/div>\n<h3>Using a system buffer<\/h3>\n<p>The first method we will see here is Buffered I\/O, defined by using the <strong>METHOD_BUFFERED<\/strong> value as a parameter of the CTL_CODE macro. Here we will not have any big news for those who read the <a href=\"https:\/\/driverentry.com.br\/en\/2008\/10\/01\/buffered-direct-or-neither\/\">previous post<\/a>. The big difference here is that in the same call to the driver, two buffers are passed to the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa363216(VS.85).aspx\">DeviceIoControl<\/a> function, one for input and another for output. Here the I\/O Manager will allocate a single system buffer with a size equal to the larger of the two. Confusing? An example helps. In a call where the application offers the input buffer with 50 bytes and an output buffer with 100 bytes, the system buffer will be allocated with 100 bytes. The I\/O Manager will copy the 50 bytes of the application&#8217;s input buffer to the system buffer. The IRP is sent to the driver, and when it is completed, the I\/O Manager copies the content of the system buffer to the application&#8217;s output buffer. The number of bytes copied back to the application is determined by the <strong>pIrp-&gt;IoStatus.Information<\/strong> field, just as in the previous post.<\/p>\n<p>An important thing to be noted here is that, since the system buffer is a single one for both the input and the output of the data, the driver needs to read the input data before starting to write the output data, which would overwrite the input buffer.<\/p>\n<p>As I have already mentioned, our example driver is going to copy the input buffer to the output buffer. Let us take a look at the implementation of our routine that will handle the IOCTL that will use a system buffer. Read the comments.<\/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;\">***     OnCopyBuffered<\/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;\">**      IOCTL handler routine responsible for<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**      copying the input buffer to the output<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">**      buffer. (using METHOD_BUFFERED)<\/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;\"><\/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;\">OnCopyBuffered(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;\">    NTSTATUS            nts;<\/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;\"><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; We get a pointer to the current stack<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      location.<\/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;\"><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Output of the obtained values.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      Notice that the input buffer and the output<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      buffer are the same. This means that you<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      cannot write to the output buffer until you<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      have read all the bytes of the input buffer.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    DbgPrint(<span style=\"color: #a31515;\">\"========== OnCopyBuffered ===========\\n\"<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">             <span style=\"color: #a31515;\">\"Input buffer address: 0x%p\\n\"<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">             <span style=\"color: #a31515;\">\"Input buffer size:    %d\\n\"<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">             <span style=\"color: #a31515;\">\"Output buffer addres: 0x%p\\n\"<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">             <span style=\"color: #a31515;\">\"Output buffer size:   %d\\n\\n\"<\/span>,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">             pIrp-&gt;AssociatedIrp.SystemBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">             pStack-&gt;Parameters.DeviceIoControl.InputBufferLength,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">             pIrp-&gt;AssociatedIrp.SystemBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">             pStack-&gt;Parameters.DeviceIoControl.OutputBufferLength);<\/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; Let us check whether the input buffer fits in the output<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      buffer before doing the copy.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: blue;\">if<\/span> (pStack-&gt;Parameters.DeviceIoControl.OutputBufferLength &lt;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        pStack-&gt;Parameters.DeviceIoControl.InputBufferLength)<\/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; Oops!<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        nts = STATUS_BUFFER_TOO_SMALL;<\/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;\">    }<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">else<\/span><\/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; Copy what for?<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/      Since the input buffer and the output buffer<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/      offered by the application are copied into a<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/      single system buffer, we do not need to make<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/      any copy. The I\/O Manager will already do that for<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/      us. We will just tell the application how many<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/      bytes are valid in the output buffer.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        nts = STATUS_SUCCESS;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        pIrp-&gt;IoStatus.Information =<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">            pStack-&gt;Parameters.DeviceIoControl.InputBufferLength;<\/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;\"><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Close the bill and draw the line.<\/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;\">    IoCompleteRequest(pIrp, IO_NO_INCREMENT);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: blue;\">return<\/span> nts;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">}<\/pre>\n<\/div>\n<h3>Locking the Application&#8217;s memory<\/h3>\n<p>Although the IOCTL is a request normally used for control, nothing stops us from using this means of communication to obtain or send data to the driver. If, in these reads or writes, large volumes of data are exchanged, the Buffered method becomes not very efficient. Using the Direct method there will be no intermediate copies into a system buffer. Nothing very different from what we already saw in the <a href=\"https:\/\/driverentry.com.br\/en\/2008\/10\/01\/buffered-direct-or-neither\/\">previous post<\/a>, but here we have two buffers in a single call. The input buffer missed school on the very day of the lesson about MDLs, and for that reason it still reaches the driver using a system buffer. That is right! Just like the buffered method. For this reason, we will not use the input buffer to send large amounts of data to the driver.<\/p>\n<p><strong>But what if I want to send a large amount of data to the driver through an IOCTL?<\/strong> Here the conversation bends a little. Note that to use the Direct method in IOCTLs, we can use either the <strong>METHOD_IN_DIRECT<\/strong> or the <strong>METHOD_OUT_DIRECT<\/strong> parameter. With the Direct method, you can use the output buffer as input for the driver. <strong>Huh?<\/strong> All right, let us go slower. Both options create an MDL to describe the pages that make up the output buffer offered by the application. When the IRP reaches the driver, you use the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms802005.aspx\">MmGetSystemAddressForMdlSafe<\/a> function to obtain a <em>System Space<\/em> pointer that maps the same physical pages offered by the application. This means that the pointer you receive will write directly to the pages offered by the application. <strong>I know! If the pointer points to the same pages as the application, then can we read the data contained in these pages?<\/strong> That is exactly it. We can send data to the driver by filling the output buffer before calling the <em>DeviceIoControl<\/em> function. So, when the driver receives the IRP, it can read this data. This allows the driver to receive large amounts of input data, but using the output buffer. The METHOD_IN_DIRECT parameter signals to the I\/O Manager that the buffer that will be used to build the MDL will be used for reading, so the buffer is tested for reads in the process of creating the MDL. Alternatively, the METHOD_OUT_DIRECT parameter indicates that the buffer will receive <strong>reads and writes<\/strong> from the driver.<\/p>\n<p>Remember that METHOD_IN_DIRECT or METHOD_OUT_DIRECT only defines the type of test that will be done on the output buffer, allowing the driver to read the output buffer. The input buffer will always come by means of a system buffer. <strong>Yeah yeah yeah, can we get to the code please?<\/strong><\/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;\">***     OnCopyDirect<\/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;\">**      IOCTL handler routine responsible for<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**      copying the input buffer to the output<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">**      buffer. (using METHOD_DIRECT_XXX)<\/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;\"><\/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;\">OnCopyDirect(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;\">    NTSTATUS            nts;<\/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;\">    PVOID               pOutputBuffer;<\/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; We get a pointer to the current stack<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      location.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    pStack = IoGetCurrentIrpStackLocation(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;\">    <span style=\"color: green;\">\/\/-f--&gt; The output pointer comes from an MDL created<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      by the I\/O Manager.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    pOutputBuffer = MmGetSystemAddressForMdlSafe(pIrp-&gt;MdlAddress,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                                                 LowPagePriority);<\/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: blue;\">if<\/span> (!pOutputBuffer)<\/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; Oops! We are out of resources to map the<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/      pages described by the MDL in System Space.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        pIrp-&gt;IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        pIrp-&gt;IoStatus.Information = <span style=\"color: purple;\">0<\/span>;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        IoCompleteRequest(pIrp, IO_NO_INCREMENT);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: blue;\">return<\/span> STATUS_INSUFFICIENT_RESOURCES;<\/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;\"><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; The input pointer, on the other hand, always comes through a<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      system buffer as in the Buffered method<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    DbgPrint(<span style=\"color: #a31515;\">\"=========== OnCopyDirect ============\\n\"<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">             <span style=\"color: #a31515;\">\"Input buffer address: 0x%p\\n\"<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">             <span style=\"color: #a31515;\">\"Input buffer size:    %d\\n\"<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">             <span style=\"color: #a31515;\">\"Output buffer addres: 0x%p\\n\"<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">             <span style=\"color: #a31515;\">\"Output buffer size:   %d\\n\\n\"<\/span>,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">             pIrp-&gt;AssociatedIrp.SystemBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">             pStack-&gt;Parameters.DeviceIoControl.InputBufferLength,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">             pOutputBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">             pStack-&gt;Parameters.DeviceIoControl.OutputBufferLength);<\/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; Let us check whether the input buffer fits in the output buffer<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      buffer before doing the copy.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">if<\/span> (pStack-&gt;Parameters.DeviceIoControl.OutputBufferLength &lt;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        pStack-&gt;Parameters.DeviceIoControl.InputBufferLength)<\/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; Oops!<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        nts = STATUS_BUFFER_TOO_SMALL;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        pIrp-&gt;IoStatus.Information = <span style=\"color: purple;\">0<\/span>;<\/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;\">    {<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/-f--&gt; In this case we will have to make the copy, since the input<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/      buffer and the output buffer are physically distinct<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        RtlCopyMemory(pOutputBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                      pIrp-&gt;AssociatedIrp.SystemBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                      pStack-&gt;Parameters.DeviceIoControl.InputBufferLength);<\/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; Signals success to the I\/O Manager and tells the application the<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/      number of valid bytes in the output buffer.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        nts = STATUS_SUCCESS;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        pIrp-&gt;IoStatus.Information =<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">            pStack-&gt;Parameters.DeviceIoControl.InputBufferLength;<\/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;\"><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Close the bill and draw the line.<\/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;\">    IoCompleteRequest(pIrp, IO_NO_INCREMENT);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: blue;\">return<\/span> nts;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">}<\/pre>\n<\/div>\n<h3>Neither Buffered I\/O nor Direct I\/O<\/h3>\n<p>This may seem repetitive to you, but in this method, indicated by the <strong>METHOD_NEITHER<\/strong> parameter, the I\/O Manager will not do anything for you. So, you will have to test the process context and also test access to the buffers as we saw in the <a href=\"https:\/\/driverentry.com.br\/en\/2008\/10\/01\/buffered-direct-or-neither\/\">previous post<\/a>. Once again, the big difference here is that we will have two buffers. The input buffer will come through <strong>pStack-&gt;Parameters.DeviceIoControl.Type3InputBuffer<\/strong> and the output buffer is obtained through <strong>pIrp-&gt;UserBuffer<\/strong>. The input buffer must be tested with <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa489870.aspx\">ProbeForRead<\/a>, since the driver will perform reads on this buffer, and the output buffer must be tested with <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms797108.aspx\">ProbeForWrite<\/a>. I think the rest the example code is able to explain. To test the process context, we use the function that was already explained in the <a href=\"https:\/\/driverentry.com.br\/en\/2008\/10\/01\/buffered-direct-or-neither\/\">previous post<\/a>.<\/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;\">***     OnCopyNeither<\/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;\">**      IOCTL handler routine responsible for<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**      copying the input buffer to the output<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">**      buffer. (using METHOD_NEITHER)<\/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;\"><\/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;\">OnCopyNeither(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;\">    NTSTATUS            nts;<\/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;\"><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; We get a pointer to the current stack<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      location.<\/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;\"><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Output of the obtained values.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    DbgPrint(<span style=\"color: #a31515;\">\"=========== OnCopyNeither ===========\\n\"<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">             <span style=\"color: #a31515;\">\"Input buffer address: 0x%p\\n\"<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">             <span style=\"color: #a31515;\">\"Input buffer size:    %d\\n\"<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">             <span style=\"color: #a31515;\">\"Output buffer addres: 0x%p\\n\"<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">             <span style=\"color: #a31515;\">\"Output buffer size:   %d\\n\\n\"<\/span>,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">             pStack-&gt;Parameters.DeviceIoControl.Type3InputBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">             pStack-&gt;Parameters.DeviceIoControl.InputBufferLength,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">             pIrp-&gt;UserBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">             pStack-&gt;Parameters.DeviceIoControl.OutputBufferLength);<\/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; Since we are using the Neither method, we have to<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      be running in the same context of the process that<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      generated the IRP, because we will access User Space in Kernel-Mode.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">if<\/span> (!EstouNoContextoDoProcessoQueGerouEssaIrp(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;\">        <span style=\"color: green;\">\/\/-f--&gt; Oops!<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        pIrp-&gt;IoStatus.Status = STATUS_INVALID_ADDRESS;<\/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_INVALID_ADDRESS;<\/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;\"><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Here we already know we are in the right context, but we still<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      need to test the buffers offered by the application.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      We do not want an unfortunate application to send an invalid<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      pointer and the system to end up in a blue screen because of it.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: blue;\">__try<\/span><\/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; The driver will perform reads on the input buffer<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        ProbeForRead(pStack-&gt;Parameters.DeviceIoControl.Type3InputBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                     pStack-&gt;Parameters.DeviceIoControl.InputBufferLength,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                     <span style=\"color: purple;\">1<\/span>);<\/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; And will perform writes on the output buffer<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        ProbeForWrite(pIrp-&gt;UserBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                      pStack-&gt;Parameters.DeviceIoControl.OutputBufferLength,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                      <span style=\"color: purple;\">1<\/span>);<\/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;\">__except<\/span>(EXCEPTION_EXECUTE_HANDLER)<\/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; Ahaaa!!<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        nts = GetExceptionCode();<\/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; Completes the IRP and curses the mother of the guy who wrote<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/      the application (unless it was you yourself).<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        pIrp-&gt;IoStatus.Status = nts;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        pIrp-&gt;IoStatus.Information = <span style=\"color: purple;\">0<\/span>;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        IoCompleteRequest(pIrp, IO_NO_INCREMENT);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: blue;\">return<\/span> nts;<\/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;\"><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Let us check whether the input buffer fits in the output buffer<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      buffer before doing the copy.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">if<\/span> (pStack-&gt;Parameters.DeviceIoControl.OutputBufferLength &lt;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        pStack-&gt;Parameters.DeviceIoControl.InputBufferLength)<\/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; Oops!<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        nts = STATUS_BUFFER_TOO_SMALL;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        pIrp-&gt;IoStatus.Information = <span style=\"color: purple;\">0<\/span>;<\/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;\">    {<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/-f--&gt; Close your eyes, say \"The blood of Jesus has power\",<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/      believe in Saint Walter Oney and copy the input<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/      buffer to the output buffer.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        RtlCopyMemory(pIrp-&gt;UserBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">                      pStack-&gt;Parameters.DeviceIoControl.Type3InputBuffer,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                      pStack-&gt;Parameters.DeviceIoControl.InputBufferLength);<\/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; Phew! Everyone alive?<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: green;\">\/\/      Signals success to the I\/O Manager and tells the application the<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        <span style=\"color: green;\">\/\/      number of valid bytes in the output buffer.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        nts = STATUS_SUCCESS;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">        pIrp-&gt;IoStatus.Information =<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">            pStack-&gt;Parameters.DeviceIoControl.InputBufferLength;<\/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;\"><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Close the bill and draw the line.<\/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;\">    IoCompleteRequest(pIrp, IO_NO_INCREMENT);<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: blue;\">return<\/span> nts;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">}<\/pre>\n<\/div>\n<h3>Compiling the example<\/h3>\n<p>To compile the example available for download, you can use the environment shortcut installed by the WDK and call <strong>Build<\/strong> from the example&#8217;s root directory. Note that in a single step we compile the driver and the test application. The figure below illustrates this. Or you can use <a href=\"http:\/\/www.osronline.com\/article.cfm?article=43\">DDKBUILD<\/a> as I already explained in this <a href=\"https:\/\/driverentry.com.br\/en\/2006\/11\/16\/kernel-visual-studio-2005\/\">other post<\/a> to compile from Visual Studio.<\/p>\n<div style=\"text-align: center;\"><img decoding=\"async\" src=\"https:\/\/driverentry.com.br\/en\/wp-content\/uploads\/2026\/07\/BuildIoctlCopy.png\" alt=\"\" \/><\/div>\n<p>&nbsp;<\/p>\n<p><strong>Fernando, one more question before you vanish into the mist. In the table of <em>Dispatch Routines<\/em>, which we fill in the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms805988.aspx\">DRIVER_OBJECT<\/a> structure, there is only one entry for <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms796116.aspx\">IRP_MJ_DEVICE_CONTROL<\/a>. How did you create a routine for each method?<\/strong> That one I am going to let the example code below answer, but if even so you still have some doubt, just send me an e-mail, which is in my <a href=\"http:\/\/www.blogger.com\/profile\/12893657520734789532\">Blogger profile<\/a>, and then we settle it with our fists.<\/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;\">***     OnDeviceControl<\/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;\">**      Here we receive all the DeviceIoControl<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**      sent to the driver and split them into<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">**      routines specific to the handling of each IOCTL.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**      The handling of all the IOCTLs could<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\"><span style=\"color: green;\">**      be in a single function, but it does not hurt to be<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\"><span style=\"color: green;\">**      organized once in a while.<\/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;\"><\/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;\">OnDeviceControl(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;\">    PIO_STACK_LOCATION  pStack;<\/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; We get a pointer to the current stack<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      location.<\/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;\"><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/-f--&gt; Gets the IOCTL code to forward it<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/      to the right routine, or not. :-)<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: blue;\">switch<\/span>(pStack-&gt;Parameters.DeviceIoControl.IoControlCode)<\/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: blue;\">case<\/span> IOCTL_COPY_BUFFERED:<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: blue;\">return<\/span> OnCopyBuffered(pDeviceObj,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                              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;\">    <span style=\"color: blue;\">case<\/span> IOCTL_COPY_DIRECT:<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: blue;\">return<\/span> OnCopyDirect(pDeviceObj,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                            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;\">    <span style=\"color: blue;\">case<\/span> IOCTL_COPY_NEITHER:<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">        <span style=\"color: blue;\">return<\/span> OnCopyNeither(pDeviceObj,<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">                             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;\"><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: green;\">\/\/-f--&gt; Oops! We received an IOCTL different from the ones<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">    <span style=\"color: green;\">\/\/      we were expecting.<\/span><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    pIrp-&gt;IoStatus.Status = STATUS_NOT_IMPLEMENTED;<\/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;\"><\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;\">    <span style=\"color: blue;\">return<\/span> STATUS_NOT_IMPLEMENTED;<\/pre>\n<pre style=\"margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;\">}<\/pre>\n<\/div>\n<p>Today I am going to say goodbye (in Portuguese) in the style of <a href=\"http:\/\/www.linkedin.com\/pub\/7\/7a3\/268\">mr4nd3r50n<\/a>, who is a friend that worked with me at <a href=\"http:\/\/www.scua.com.br\">SCUA<\/a>.<\/p>\n<p>Intel mais, j\u00e1 vou Windows!<\/p>\n<p class=\"download\"><a href=\"http:\/\/www.driverentry.com.br\/samples\/IoctlCopy.zip\">IoctlCopy.zip<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>After a pinch of virtual memory to understand the most relevant concepts and take a good stroll through the data-transfer methods between application and driver, today we are going to close this trilogy talking about the data-transfer methods in IOCTLs. If you do not know how to create or use IOCTLs, this other post may [&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-370","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/posts\/370","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=370"}],"version-history":[{"count":2,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/posts\/370\/revisions"}],"predecessor-version":[{"id":377,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/posts\/370\/revisions\/377"}],"wp:attachment":[{"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/media?parent=370"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/categories?post=370"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/driverentry.com.br\/en\/wp-json\/wp\/v2\/tags?post=370"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}