Develop a Virtual COM port driver for windows XP & above

I think the first time the OP entered the address is mistyped a lower-case “L” at the end of the number as a 1. This is born out by the fact that in the other two instances the last character is an ell. This is further evidenced by counting digits. Without the “L” you have 8, with it a very suspicious 9.

* Bob

? Bob Ammerman
? xxxxx@ramsystems.biz
716.864.8337

138 Liston St
Buffalo, NY 14223
www.ramsystems.biz

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-613136-
xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Tuesday, July 26, 2016 5:58 PM
To: Windows System Software Devs Interest List
> Subject: Re: [ntdev] Develop a Virtual COM port driver for windows XP &
> above
>
> xxxxx@chetu.com wrote:
> >
> > I created a new USB UMDF V1 driver project & trying to write a simple USB
> driver that could write to my USB printer.
> >
> > In the new project I added code in CMyDevice::OnPrepareHardware
> function to create USB target device, then I retrieved the interface & End
> point information from my device & selected the appropriate End points &
> interface. I have added the CMyDevice::OnPrepareHardware function to QI
> so now it is getting invoked by the frame work.
> >
> > I also added the code for CMyIoQueue::Onwrite function & added it to the
> QueryInterface as well.
> >
> > When I install the USB driver I found that the CMyIoQueue::Onwrite()
> function gets invokes once I call writefile() function from my Win32
> application.
>
> That’s good. A lot of stuff has to be working to get that far.
>
>
> > While debugging the CMyDevice::OnPrepareHardware function I found out
> > that when I retrieve the address of the output Endpoints(pIUsbPipe)
> > through
> >
> > if (pIUsbPipe->IsOutEndPoint() && (UsbdPipeTypeBulk ==
> > pIUsbPipe->GetType())) {
> > m_pIUsbOutputPipe = pIUsbPipe; }
> >
> > I get a valid a 32 bit address but along with the address i get the
> > following statement “Information not available no symbols were loaded for
> WUDFX.dl”
> >
> > when I take pIUsbPipe in the watch window it lokes like this:
> > 0x009368b81> WUDFX.dl>.
> > but the code doesn’t break or throw any exception.
>
> This is a data structure on the heap. It’s probably trying to load symbols so it
> can show you the contents of IWDFUsbTargetPipe, but because that’s an
> interface, it doesn’t contain any data, so there’s nothing to look at anyway. It
> is unusual that it would be at an odd address, however. If you dump the
> memory at that address, does it look like a C++ interface? That is, a set of
> function pointers?
>
>
> > Then when I invoke the writefile() Win32 API from my application the
> > control comes to CMyIoQueue::Onwrite function then I step into it till
> > i reach the following code line
> >
> > pOutputPipe = m_Device->GetOutputPipe()
> >
> > when I step over this line & add pOutputPipe to watch window i get the
> following address against it
> > 0x009368b8l> > WUDFX.dl>
>
> Good that it is the same address, even if it is an odd number.
>
>
> > hr = pOutputPipe->FormatRequestForWrite(
> > pWdfRequest,
> > NULL, //pFile
> > pInputMemory,
> > NULL, //Memory offset
> > NULL //DeviceOffset
> > );
> >
> > I get the following exception
> >
> > pOutputPipe-> was nullptr
>
> Where do you see that exception? Are you seeing that in the watch
> window? If so, forget about it. Don’t ever trust the debugger, especially
> with local variables. Too much information is lost during compilation. If the
> driver did not crash at that point, then obviously the pointer was not null.
> You can try debugging the assembler, or printing stuff out to the debug log.
>
>
> > So question is in the previous line pOutputPipe was pointing to 0x009368b8l
> address then how can it be a nullptr.??
>
> Clearly it can’t, so it isn’t.
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list online at:
> http:
>
> MONTHLY seminars on crash dump analysis, WDF, Windows internals and
> software drivers!
> Details at http:
>
> To unsubscribe, visit the List Server section of OSR Online at
> http:</http:></http:></http:>

Robert Ammerman wrote:

I think the first time the OP entered the address is mistyped a lower-case “L” at the end of the number as a 1. This is born out by the fact that in the other two instances the last character is an ell. This is further evidenced by counting digits. Without the “L” you have 8, with it a very suspicious 9.

Bah, shame on me for not noticing that.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

>Where do you see that exception? Are you seeing that in the watch

window? If so, forget about it. Don’t ever trust the debugger,
especially with local variables. Too much information is lost during
compilation. If the driver did not crash at that point, then obviously
the pointer was not null. You can try debugging the assembler, or
printing stuff out to the debug log.

No I am not seeing the exception in the watch window. The exception flashes on a popup screen that appears once I execute hr = pOutputPipe->FormatRequestForWrite( line of code. & i think its the driver that crashed at this point because the exception popup window reappears when i click continue.

In order to get to the root of the issue I placed a break point at hr = pOutputPipe->FormatRequestForWrite function & when the breakpoint was hit I opened the Disassembly window which looks like this

hr = pOutputPipe->FormatRequestForWrite(
0F784202 6A 00 push 0
0F784204 6A 00 push 0
0F784206 8B 45 FC mov eax,dword ptr [pInputMemory]
0F784209 50 push eax
0F78420A 6A 00 push 0
0F78420C 8B 4D 10 mov ecx,dword ptr [pWdfRequest]
0F78420F 51 push ecx
0F784210 8B 55 F8 mov edx,dword ptr [pOutputPipe]
0F784213 8B 02 mov eax,dword ptr [edx]
0F784215 8B 4D F8 mov ecx,dword ptr [pOutputPipe]
0F784218 51 push ecx
0F784219 8B 50 2C mov edx,dword ptr [eax+2Ch] //Here the exception occurs
0F78421C FF D2 call edx
0F78421E 89 45 F4 mov dword ptr [hr],eax

Now in the initial 7 lines of the dissembler code it just fetches the arguments of the pOutputPipe->FormatRequestForWrite function & pushes it to the stack.

0F784210 8B 55 F8 mov edx,dword ptr [pOutputPipe]

In the above line of code it retrieves the value pointed by pOutputPipe & copies it to the data register(edx). A 32 bit value(10450352) gets copied to edx.

0F784213 8B 02 mov eax,dword ptr [edx]

Now it again de-references the 32bit value(10450352) that it obtained from the previous instruction. Now the value that is obtains after de-referencing is zero. so eax = 0

0F784215 8B 4D F8 mov ecx,dword ptr [pOutputPipe]
0F784218 51 push ecx
0F784219 8B 50 2C mov edx,dword ptr [eax+2Ch]

Here as eax was assigned zero in the previous instruction so ptr[eax+2Ch] throws the exception.

that says read access voilation:
pOutputPipe-> was nullptr.

What am i missing here.?

I think the first time the OP entered the address is mistyped a lower-case “L”
at the end of the number as a 1. This is born out by the fact that in the other
two instances the last character is an ell. This is further evidenced by
counting digits. Without the “L” you have 8, with it a very suspicious 9.

You are absolutely right that was a typing mistake. sorry for the confusion.

If you dump the memory at that address, does it look
like a C++ interface? That is, a set of function pointers?

Is it possible to dump the memory in visual studio.?

One more thing that I noticed while debugging the code for resolving the crash issue is that in CMyDevice::OnPrepareHardware function where I retrieve the output Endpoint through the following code

if (pIUsbPipe->IsOutEndPoint() && (UsbdPipeTypeBulk == pIUsbPipe->GetType()))
{
m_pIUsbOutputPipe = pIUsbPipe;
}

And try to know the value of m_pIUsbOutputPipe by placing my mouse over it. It displays m_pIUsbOutputPipe 0x00956698 with an arrow in front of it, when i expanded the arrow it shows IWDFIoTarget |{…} with an arrow in front of it, when it] expanded the arrow it shows IWDFObject | {…} with an arrow in front of it, when i expanded the arrow it shows IUnknown | {…} with an arrow in front of it, when i expanded the arrow it shows _vfptr 0x5032e0b0 with an arrow in front of it, when i expanded the arrow it shows [0] 0x50364620
[1] 0x5036469b
[2] 0x5036466e

here I understand that it shows the hierarchy of the interfaces from which m_IUsbOutputPipe object is derived & _vfptr is the array of function pointers that Tim was talking about in the following statement

…If you dump the memory at that address, does it look
like a C++ interface? That is, a set of function pointers?

but when i perform the same operation on pOutputPipe in CMyIoQueue::Onwrite after the execution of the following line of code

pOutputPipe = m_Device->GetOutputPipe()

to see the hierarchy of interfaces & the list of function pointers under _vfptr

then _vfptr, [0], [1] & [2] shows 0x00000000 value against it. Now I am not sure from where does the set of function pointers get these NULL value & Im sure this is the reason for which I am getting the above exception & my driver is crashing.

xxxxx@chetu.com wrote:

One more thing that I noticed while debugging the code for resolving the crash issue is that in CMyDevice::OnPrepareHardware function where I retrieve the output Endpoint through the following code

but when i perform the same operation on pOutputPipe in CMyIoQueue::Onwrite after the execution of the following line of code

pOutputPipe = m_Device->GetOutputPipe()

to see the hierarchy of interfaces & the list of function pointers under _vfptr

then _vfptr, [0], [1] & [2] shows 0x00000000 value against it. Now I am not sure from where does the set of function pointers get these NULL value & Im sure this is the reason for which I am getting the above exception & my driver is crashing.

Yes. The implication is that your vtbl is zero, as if someone has
Released the object.

There is something very strange about this sample. As it is written,
the code is totally wrong, from a COM point of view. The code in
CMyDevice::CreateUsbIoTargets calls RetrieveUsbPipeObject in a loop,
each of which returns an IWDFUsbTargetPipe interface, presumably with a
reference count of 1. The code then checks the type of pipe, and saves
a copy in a member variable, like m_pIUsbInputPipe or
m_pIUsbOutputPipe. Those are plain, ordinary pointers, which means they
do not call AddRef. After all of that, the code calls SAFE_RELEASE
unconditionally, with a comment saying “release creation reference”.

In straight COM, that would be totally wrong, because that “release”
would invalidate the copies we just made. The member variables would
not be null, but they would be pointing into empty space. The only way
this could work is of m_pIUsbInputPipe and m_pIUsbOutputPipe were smart
pointers, like CComPtr or
_com_ptr_t, instead of plain dumb pointers, but they
are not.

My next statement was going to be “since that code has been in the WDK
for a decade, I assume I must be missing something”, but to my great
surprise, when I went back to the original UMDF sample in the Vista
(6000) DDK, it only does the SAFE_RELEASE if it does not grab a copy of
the pointer. So, the original sample is correct from a COM point of view.

I don’t understand that change, especially since it SEEMS to be the
direct cause of your problem. If it were me, I would cut that call to
SAFE_RELEASE(pIUsbPipe); and paste a copy just after each call to
pIUsbPipe->DeleteWdfObject();. (Actually, if it were me I would convert
every interface reference in the whole driver to CComPtr, but that’s
another chapter.)

I hope someone will correct my interpretation here, since this seems so
egregious. Maybe this is why the COM-based UMDF 1.x is now dead.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

>The code in

CMyDevice::CreateUsbIoTargets calls RetrieveUsbPipeObject in a loop,
each of which returns an IWDFUsbTargetPipe interface, presumably with a
reference count of 1. The code then checks the type of pipe, and saves
a copy in a member variable, like m_pIUsbInputPipe or
m_pIUsbOutputPipe

Im not using CMyDevice::CreateUsbIoTargets & RetrieveUsbPipeObject, rather I retrieving the Endpoint information in MyDevice::OnPrepareHardware, which calls usbFactory->CreateUsbTargetDevice(&usbDevice) to create the targwet device & then I retrieve the interfaces by m_FxUsbDevice->RetrieveUsbInterface() & then get the number of End points & traverse through each Enpoints in a loop to retrieve the output bulk Endpoint.

If it were me, I would cut that call to
SAFE_RELEASE(pIUsbPipe); and paste a copy just after each call to
pIUsbPipe->DeleteWdfObject();

I did the same & now my pOutputPipe->FormatRequestForWrite() function doesn’t crash & gives S_OK as the return value. So thank you once again Tim.

Then the control enters ForwardFormattedRequest(pWdfRequest, pOutputPipe) function, inside this function I have the

hrSend = pRequest->Send(pOutputPipe, 0, 0); function that send my request to the lower driver WinUSB.

This code after execution returns a 0xd0000184 error code. Now I searched the Winerror.h file for this error code but I didn’t find any. The error code looks weird to me.

Now I am trying to debug this issue so I steped in to the Deassembler window.

219: hrSend = pRequest->Send(pIoTarget,
0F1D3D21 6A 00 push 0
0F1D3D23 6A 00 push 0
0F1D3D25 6A 02 push 2
0F1D3D27 8B 4D 0C mov ecx,dword ptr [pIoTarget]
0F1D3D2A 51 push ecx
0F1D3D2B 8B 55 08 mov edx,dword ptr [pRequest]

Now in the above line of code the value at pRequest is assigned to edx & in the below line of code the value of at pRequest is assigned to ecx, but to my suprise there two vales are diffrent from each other. How can it be possible that on de-referencing the same address I am getting two diff-rent values
0F1D3D2E 8B 02 mov eax,dword ptr [edx]
0F1D3D30 8B 4D 08 mov ecx,dword ptr [pRequest]

219: hrSend = pRequest->Send(pIoTarget,
0F1D3D33 51 push ecx
0F1D3D34 8B 50 5C mov edx,dword ptr [eax+5Ch]

0F1D3D37 FF D2 call edx
0F1D3D39 89 45 F8 mov dword ptr [hrSend],eax
220: WDF_REQUEST_SEND_OPTION_SYNCHRONOUS, //flags
221: 0); //timeout

I think I am facing the same issue here which I faced in pOutputPipe->FormatRequestForWrite() (but the good part is, this time my driver is not crashing) as in this case as well after the execution of

0F1D3D2E 8B 02 mov eax,dword ptr [edx]

eax is assigned 0 so the line of code

0F1D3D34 8B 50 5C mov edx,dword ptr [eax+5Ch]

produces the an error as ptr[0+5ch] give a invalid data.

So I have commented out all the SAFE_RELEASE in my driver code base but i pRequest->send() trows the same error code

Now Im creating my own request in the Onwrite function through

HRESULT CreateRequest(
[in, optional] IUnknown *pCallbackInterface,
[in, optional] IWDFObject *pParentObject,
[out] IWDFIoRequest **ppRequest
);

and send this request to the lower driver by calling the send() method.

Please suggest me a way out of this.

I have a query on which I need some clarification. As of now in my PC application i am opening the symbolic link of my USB printer through CreateFile Win32 APi & then I am writing a character( “A”) to it through WriteFile API. Now if my USB printer’s Firmware is programmed to receive data in a certain format (for eg: in order to make my printer identify A I need to send "

A

" ) will my pRequest->send() method of my USB driver succeed or it wil throw some error. As per my understanding it should succeed, the USB printer might not respond to “A” but my driver’s pRequest->send() function should succeed.

Please share your thoughts on this as well.

xxxxx@chetu.com wrote:

> If it were me, I would cut that call to
> SAFE_RELEASE(pIUsbPipe); and paste a copy just after each call to
> pIUsbPipe->DeleteWdfObject();
I did the same & now my pOutputPipe->FormatRequestForWrite() function doesn’t crash & gives S_OK as the return value. So thank you once again Tim.

I filed a bug report against the sample. Maybe someone can explain it
to me.

Then the control enters ForwardFormattedRequest(pWdfRequest, pOutputPipe) function, inside this function I have the

hrSend = pRequest->Send(pOutputPipe, 0, 0); function that send my request to the lower driver WinUSB.

This code after execution returns a 0xd0000184 error code. Now I searched the Winerror.h file for this error code but I didn’t find any. The error code looks weird to me.

C0000184 would be STATUS_INVALID_DEVICE_STATE. That may be irrelevant.

Now in the above line of code the value at pRequest is assigned to edx & in the below line of code the value of at pRequest is assigned to ecx, but to my suprise there two vales are diffrent from each other. How can it be possible that on de-referencing the same address I am getting two diff-rent values

They can’t. You are reading something incorrectly in the debugger.

I think I am facing the same issue here which I faced in pOutputPipe->FormatRequestForWrite() (but the good part is, this time my driver is not crashing) as in this case as well after the execution of

0F1D3D2E 8B 02 mov eax,dword ptr [edx]

eax is assigned 0 so the line of code

0F1D3D34 8B 50 5C mov edx,dword ptr [eax+5Ch]

produces the an error as ptr[0+5ch] give a invalid data.

So I have commented out all the SAFE_RELEASE in my driver code base but i pRequest->send() trows the same error code

That’s clearly not the right answer.

It’s damn near impossible for us to help you with this, because we don’t
have any idea what you’ve done to the code. You started from a sample,
but you’ve heavily modified it. Again here, the implication is that
your pRequest has been released. Where did pRequest come from? Is it a
parameter? Are you sure you passed in the right value?

You’re going to have to show us your code to make any more progress.

I have a query on which I need some clarification. As of now in my PC application i am opening the symbolic link of my USB printer through CreateFile Win32 APi & then I am writing a character( “A”) to it through WriteFile API. Now if my USB printer’s Firmware is programmed to receive data in a certain format (for eg: in order to make my printer identify A I need to send "

A

" ) will my pRequest->send() method of my USB driver succeed or it wil throw some error. As per my understanding it should succeed, the USB printer might not respond to “A” but my driver’s pRequest->send() function should succeed.

It’s just a USB bulk write. There’s no interpretation of the data in
any way – it’s a pipe from you to your device. If your hardware does
not reject the USB transfer, then the Send() function will succeed.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Tim Roberts wrote:

xxxxx@chetu.com wrote:
>> If it were me, I would cut that call to
>> SAFE_RELEASE(pIUsbPipe); and paste a copy just after each call to
>> pIUsbPipe->DeleteWdfObject();
> I did the same & now my pOutputPipe->FormatRequestForWrite() function doesn’t crash & gives S_OK as the return value. So thank you once again Tim.
I filed a bug report against the sample. Maybe someone can explain it
to me.

I already got a response pointing to this article:

Please see the “Managing References to Framework Objects”
documentation here -
https://msdn.microsoft.com/en-us/windows/hardware/drivers/wdf/managing-the-lifetime-of-objects

which claims that the reference counts in UMDF are strictly decorative
and serve no function. I don’t know how to reconcile that with the
results you saw, and I don’t quite understand why they would implement
something based on COM but entirely eschew the COM rules. Ordinarily I
would go look it up myself, but as far as I know the UMDF 1 sources have
never been released.

I suppose I should ask the obvious question. Why did you not start with
UMDF v2? UMDF v1 is dead.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

>I suppose I should ask the obvious question. Why did you not start with

UMDF v2? UMDF v1 is dead.

Thats coz we are developing this driver for Windows vista & above & as per my understanding UMDF v2 are supported only on Windows 8 & above. so that was the reason we were forced to start with UMDFv1 :frowning:

>It’s damn near impossible for us to help you with this, because we don’t

have any idea what you’ve done to the code. You started from a sample,
but you’ve heavily modified it…

This time i did not start with a sample project, rather I created a new USB UMDF V1 project & made some addition to the code, as per my requirements, by taking reference from a UMDF_fx sample driver code. Now the additions that i made to the code are as follows.

The first function that I modified was

virtual HRESULT STDMETHODCALLTYPE OnPrepareHardware(__in IWDFDevice *FxDevice )

{
UCHAR NumEndPoints = 0;
HRESULT hr;
IWDFUsbTargetFactory *usbFactory = NULL;
IWDFUsbTargetDevice *usbDevice = NULL;

/*********** New added code starts*************/
IWDFUsbInterface * pIUsbInterface = NULL;
IWDFUsbTargetPipe * pIUsbPipe = NULL;
/*********** New added code ends*************/
PWSTR deviceName = NULL;
DWORD deviceNameCch = 0;

// Get the device name.
// Get the length to allocate first
/*********** New added code starts*************/
hr = m_FxDevice->RetrieveDeviceName(NULL, &deviceNameCch);

if (SUCCEEDED(hr))
{
deviceName = new WCHAR[deviceNameCch];

if (deviceName == NULL)
{
hr = E_OUTOFMEMORY;
}
}

// Get the actual name
if (SUCCEEDED(hr))
{
hr = m_FxDevice->RetrieveDeviceName(deviceName, &deviceNameCch);

}

/*********** New added code ends*************/

hr = m_FxDevice->QueryInterface(IID_PPV_ARGS(&usbFactory));

if (FAILED(hr))
{
goto Exit;
}

hr = usbFactory->CreateUsbTargetDevice(&usbDevice);

if (FAILED(hr))
{
goto Exit;
}
else {

// Store a weak reference in a private data member. Because it is an object
// in the WDF object tree, the object will be alive until we delete it
// explicitly in ReleaseHardware.

m_FxUsbDevice = usbDevice;
m_FxUsbDevice->Release();

}
/*********** New added code starts*************/
if (SUCCEEDED(hr))
{
//Here I get the number of interfaces of my device
UCHAR NumInterfaces = m_FxUsbDevice->GetNumInterfaces();

WUDF_TEST_DRIVER_ASSERT(1 == NumInterfaces);

//As my device has only one interface Here I retrieve the the interface information & store in a IWDFUsbInterface * type pointer
hr = m_FxUsbDevice->RetrieveUsbInterface(0, &pIUsbInterface);
if (FAILED(hr))
{

}
else
{
//Here I then store the interface to MyClass Interface object
m_pIUsbInterface = pIUsbInterface;

pIUsbInterface->Release();
}
}
if (SUCCEEDED(hr))
{
// here I get the number of Endpoints in my interface
NumEndPoints = pIUsbInterface->GetNumEndPoints();

if (NumEndPoints != NUM_PRINTERUSB_ENDPOINTS) { //For printer device
hr = E_UNEXPECTED;

}
}
if (SUCCEEDED(hr))
{
//I then traverse through Each Points to get my Bulk input Endpoint & my Bulk output Endpoint.
for (UCHAR PipeIndex = 0; PipeIndex < NumEndPoints; PipeIndex++)
{
hr = pIUsbInterface->RetrieveUsbPipeObject(PipeIndex,
&pIUsbPipe);

if (FAILED(hr))
{

}
else
{
if (pIUsbPipe->IsInEndPoint() && (UsbdPipeTypeBulk == pIUsbPipe->GetType()))
{
m_pIUsbInputPipe = pIUsbPipe;
}
else
{
pIUsbPipe->DeleteWdfObject();
}
if (pIUsbPipe->IsOutEndPoint() && (UsbdPipeTypeBulk == pIUsbPipe->GetType()))
{
m_pIUsbOutputPipe = pIUsbPipe;

//m_ppIUsbOutputPipe = pIUsbPipe;
}
else
{
pIUsbPipe->DeleteWdfObject();
}
//When my FormatRequestForWrite() function was throwing exceptions I commented out the below line to make it work properly. This is where my pIUsbPipe was getting released. but im still not sure why the release of a local pointer(pIUsbPipe) affecting my Global pointer(m_pIUsbOutputPipe)
//SAFE_RELEASE(pIUsbPipe); //release creation reference
}
}

if (NULL == m_pIUsbInputPipe || NULL == m_pIUsbOutputPipe)
{
hr = E_UNEXPECTED;
}
}

/*********** New added code ends*************/

Exit:
DriverSafeRelease(usbDevice);
DriverSafeRelease(usbFactory);
return hr;
}

Then I made some modification to

class CMyIoQueue :
public CComObjectRootEx,
public IQueueCallbackDeviceIoControl,
public IQueueCallbackWrite //I added to be able to use the Onwrite() function of IQueueCallbackWrite calss

{

public:

DECLARE_NOT_AGGREGATABLE(CMyIoQueue)

BEGIN_COM_MAP(CMyIoQueue)
COM_INTERFACE_ENTRY(IQueueCallbackWrite) // then Queried IQueueCallbackWrite class so that the framework knows about it.
COM_INTERFACE_ENTRY(IQueueCallbackDeviceIoControl)

END_COM_MAP()

CMyIoQueue() :
m_FxQueue(NULL),
m_Device(NULL)
{
}

~CMyIoQueue()
{
// empty
}

HRESULT Initialize( in IWDFDevice *FxDevice, in CMyDevice MyDevice);

void CMyIoQueue::ForwardFormattedRequest(In IWDFIoRequest
pRequest, In IWDFIoTarget* pIoTarget);

static HRESULT CreateInstanceAndInitialize( in IWDFDevice *FxDevice, in CMyDevice MyDevice, __out CMyIoQueueQueue);

HRESULT Configure(VOID )
{
return S_OK;
}

virtual VOID STDMETHODCALLTYPE OnDeviceIoControl(__in IWDFIoQueue pWdfQueue, in IWDFIoRequest *pWdfRequest, in ULONG ControlCode, in SIZE_T InputBufferSizeInBytes, in SIZE_T OutputBufferSizeInBytes);

/
******* New added code starts*************/
//Then I added the declaration of OnWrite function to MyIoQueue class
virtual VOID STDMETHODCALLTYPE OnWrite(In IWDFIoQueue pWdfQueue, In IWDFIoRequest pWdfRequest, In SIZE_T NumOfBytesToWrite);
/
********* New added code ends ************* /

private:

IWDFIoQueue * m_FxQueue;
CMyDevice * m_Device;
};

Now these are all the changes that I made to the new USB UMDF v1 driver project that I had created.

Now for your reference let me also show you my CMyIoQueue::OnWrite function

VOID STDMETHODCALLTYPE CMyIoQueue::OnWrite(In IWDFIoQueue pWdfQueue, In IWDFIoRequest pWdfRequest,_ In_ SIZE_T BytesToWrite)

{
UNREFERENCED_PARAMETER(pWdfQueue);

HRESULT hr = S_OK;
IWDFMemory * pInputMemory = NULL;
IWDFUsbTargetPipe * pOutputPipe = NULL;

pOutputPipe = m_Device->GetOutputPipe();
pWdfRequest->GetInputMemory(&pInputMemory);

hr = pOutputPipe->FormatRequestForWrite(
pWdfRequest,
NULL, //pFile
pInputMemory,
NULL, //Memory offset
NULL //DeviceOffset
);

if (FAILED(hr))
{
pWdfRequest->Complete(hr);
}
else
{
ForwardFormattedRequest(pWdfRequest, pOutputPipe);
}

SAFE_RELEASE(pInputMemory);

return;
}

>Where did pRequest come from? Is it a
>parameter? Are you sure you passed in the right value? )

IWDFIoRequest * type pointer is passed on to CMyIoQueue::OnWrite() by the framework through a parameter pWdfRequest. When WriteFile Win21API is called. It holds the write request that is generated by initiated by the Win32 API & need to be passed to the lower driver in the device stack in order to accomplish the write operation.
Now this IWDFIoRequest * type pointer is passes on to FormatRequestForWrite() function & then to ForwardFormattedRequest()
In ForwardFormattedRequest() function has a parameter In IWDFIoRequest
pRequest that receives this request pointer.

void CMyIoQueue::ForwardFormattedRequest(In IWDFIoRequest
pRequest, In IWDFIoTarget* pIoTarget)
{
//First set the completion callback
IRequestCallbackRequestCompletion * pCompletionCallback = NULL;
HRESULT hrQI = this->QueryInterface(IID_PPV_ARGS(&pCompletionCallback));
WUDF_TEST_DRIVER_ASSERT(SUCCEEDED(hrQI) && (NULL != pCompletionCallback));

pRequest->SetCompletionCallback(
pCompletionCallback,
NULL
);

pCompletionCallback->Release();
pCompletionCallback = NULL;

//Send down the request

HRESULT hrSend = S_OK;
hrSend = pRequest->Send(pIoTarget,0,0);

if (FAILED(hrSend))
{
pRequest->CompleteWithInformation(hrSend, 0);
}

return;
}

It is in this pRequest->Send(pIoTarget,0,0) I am getting a error code of 0xd0000184

>I suppose I should ask the obvious question. Why did you not start with
>UMDF v2? UMDF v1 is dead.

Thats coz as per our client’s requirement this driver should be support by Windows XP & above & as per my
understanding UMDF v2 are supported only on Windows 8 & above. so that was thereason we were forced to start with UMDFv1 :frowning:

Got it.

In that case, I would advise you to use KMDF and NOT do your project in user-mode. Otherwise, you’re using a Framework that – while certainly supported – is no longer being actively enhanced and is clearly not “the way forward” indicated by MSFT.

Peter
OSR
@OSRDrivers

xxxxx@chetu.com wrote:

> It’s damn near impossible for us to help you with this, because we don’t
> have any idea what you’ve done to the code. You started from a sample,
> but you’ve heavily modified it…
This time i did not start with a sample project, rather I created a new USB UMDF V1 project & made some addition to the code, as per my requirements, by taking reference from a UMDF_fx sample driver code. Now the additions that i made to the code are as follows.

//When my FormatRequestForWrite() function was throwing exceptions I commented out the below line to make it work properly. This is where my pIUsbPipe was getting released. but im still not sure why the release of a local pointer(pIUsbPipe) affecting my Global pointer(m_pIUsbOutputPipe)
//SAFE_RELEASE(pIUsbPipe); //release creation reference

You can’t think of it as releasing a local pointer. What you are
releasing is an OBJECT. The pointer is just a handle to it. You have
one pointer to the object in pIUsbPipe, and you have another pointer to
that object in m_pIUsbInputPipe. When you release an object in COM,
that causes the object to be destroyed. It doesn’t (CAN’T) change any
of the pointers to that object, but those pointers now point into empty
space, which appears to be exactly what happened to you.

This is the whole reason why we use reference counting. In a real COM
app, when you do this:
m_pIUsbInputPipe = pIUsbPipe;
you immediately follow it by:
m_pIUsbInputPipe->AddRef();
to tell the world that you now have two references to the object. That
way, releasing the local pointer decrements the count to 1, so it can’t
be deleted. The wrapper classes like CComPtr and _com_ptr_t handle all
of that automatically.

I keep reading that UMDF doesn’t follow the COM reference counting rules
(which surprises me), but your code certainly doesn’t seem to back that
up. Perhaps you should break into your code just below that point, and
set a “write breakpoint” on the memory that pIUsbPipe points to. That
way, you can get a break at the point where that memory changes. That
should at least tell you when that happens.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.