windows 与 USB设备进行数据交换实现

2019-12-5 C++

需求:上位机通过USB与下位机进行数据交互

实现:

打开设备:


static LONG HidOpen(DWORD HidUsbMian, DWORD HidUsbSub)
{
//hid设备GUID
CString strHidPath(_T(""));
HDEVINFO deviceInfoSet = INVALID_HANDLE_VALUE;
PSP_DEVICE_INTERFACE_DETAIL_DATA pDeviceInterfaceDetailData = NULL;
SP_DEVINFO_DATA devinfoData;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
ZeroMemory(&deviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
ZeroMemory(&devinfoData, sizeof(SP_DEVINFO_DATA));
devinfoData.cbSize = sizeof(SP_DEVINFO_DATA);
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
GUID interfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} };
deviceInfoSet = SetupDiGetClassDevsA(&interfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
int deviceIndex = 0;
BOOL bExit = FALSE;
for ( ; bExit == FALSE; )
{
do
{
HANDLE writeHandle = INVALID_HANDLE_VALUE;
DWORD dwRequiredSize = 0;
BOOL res = SetupDiEnumDeviceInterfaces(deviceInfoSet,
NULL,
&interfaceClassGuid,
deviceIndex,
&deviceInterfaceData);
if (res == FALSE)
{
bExit = TRUE;
break;
}

BOOL bFind = FALSE;
for (int i = 0; ; ++i)
{
TCHAR szDriverName[MAX_PATH] = { 0 };
res = SetupDiEnumDeviceInfo(deviceInfoSet, i, &devinfoData);
if (res == FALSE)
{
break;
}
res = SetupDiGetDeviceRegistryProperty(deviceInfoSet, &devinfoData,
   SPDRP_CLASS, NULL, reinterpret_cast<PBYTE>(szDriverName), sizeof(szDriverName), NULL);
if (res == FALSE)
{
break;
}
if (_tcscmp(szDriverName, _T("HIDClass")) == 0) 
{
res = SetupDiGetDeviceRegistryProperty(deviceInfoSet, &devinfoData,
   SPDRP_DRIVER, NULL, reinterpret_cast<PBYTE>(szDriverName), sizeof(szDriverName), NULL);
if (res == TRUE)
{
bFind = TRUE;
break;
}
}
}
//不是有效的设备的继续
if (FALSE == bFind)
{
break;
}
res = SetupDiGetDeviceInterfaceDetail(deviceInfoSet,
&deviceInterfaceData,
NULL,
0,
&dwRequiredSize,
NULL);
pDeviceInterfaceDetailData = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(dwRequiredSize));
pDeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
res = SetupDiGetDeviceInterfaceDetail(deviceInfoSet,
&deviceInterfaceData,
pDeviceInterfaceDetailData,
dwRequiredSize,
NULL,
NULL);

writeHandle = CreateFile(pDeviceInterfaceDetailData->DevicePath, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
/*FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
if (writeHandle == INVALID_HANDLE_VALUE) 
{
break;
}
HIDD_ATTRIBUTES attrib;
attrib.Size = sizeof(HIDD_ATTRIBUTES);
HidD_GetAttributes(writeHandle, &attrib);
/*
if ((HidUsbMian == 0x0 || attrib.VendorID == HidUsbMian)
&& (HidUsbSub == 0x0 || attrib.ProductID == HidUsbSub))
*/
if (attrib.VendorID == HidUsbMian && attrib.ProductID == HidUsbSub)
{
strHidPath = pDeviceInterfaceDetailData->DevicePath;
}
CloseHandle(writeHandle);
} while (0);
if (pDeviceInterfaceDetailData != NULL)
{
free(pDeviceInterfaceDetailData);
pDeviceInterfaceDetailData = NULL;
}
if (strHidPath != _T(""))
{
break;
}
++deviceIndex;
}
if (strHidPath == _T(""))
{
return 0;
}

HANDLE openHandle = CreateFile(strHidPath, 
GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 
FILE_FLAG_OVERLAPPED, 0);
HANDLE readHandle = CreateFile(strHidPath, 
GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 
0, 0);
/*FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
if (openHandle == INVALID_HANDLE_VALUE)
{
return NULL;
}
do
{
PHIDP_PREPARSED_DATA ppData = NULL;
HIDP_CAPS caps;
if (0)//0 == HidD_SetNumInputBuffers(openHandle, 512))
{
::OutputDebugString(_T("-------------HidD_SetNumInputBuffers Failed-------\r\n"));
break;
}
if (0 == HidD_GetPreparsedData(openHandle, &ppData))
{
::OutputDebugString(_T("-------------HidD_GetPreparsedData Failed-------\r\n"));
break;
}

NTSTATUS ntStatus = HidP_GetCaps(ppData, &caps);
if (ntStatus != HIDP_STATUS_SUCCESS)
{
::OutputDebugString(_T("-------------HidP_GetCaps Failed-------\r\n"));
break;
}
{
CString strMsg(_T(""));
strMsg.Format(_T("--Input Length[%d]---Output Length[%d]----\r\n"), caps.InputReportByteLength, caps.OutputReportByteLength);
::OutputDebugString(strMsg);
}
HidD_FreePreparsedData(ppData);
PHidDevice dev = NewHidDevice();
if (dev != NULL)
{
dev->deviceHandle = openHandle;
dev->deviceReadHandle = readHandle;
int nBufLen = (strHidPath.GetLength() + 1);
dev->devicePath = new TCHAR[nBufLen];
if (dev->devicePath != NULL)
{
memset(dev->devicePath, 0, nBufLen * sizeof(TCHAR));
_tcscpy_s(dev->devicePath, nBufLen, strHidPath.GetString());
}
}
return reinterpret_cast<long>(dev);
} while (0);

if (openHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(openHandle);
openHandle = INVALID_HANDLE_VALUE;
}
if (readHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(readHandle);
readHandle = INVALID_HANDLE_VALUE;
}
return 0;
}
读数据:

ReadFile(handle, buf, 18, &dwReaded, NULL) ;

写数据:

OVERLAPPED ol;
memset(&ol, 0, sizeof(OVERLAPPED));
ol.hEvent = ::CreateEventA(NULL, TRUE, FALSE, NULL);
do
{
int nCurLen = nBufSize >= 8 ? 8 : nBufSize;
memset(buf, 0, 11);
buf[0] = 0x00;
buf[1] = LOBYTE(nCurLen);
buf[2] = 0x00;
memcpy(buf + 3, pTmp, nCurLen);
ResetEvent(ol.hEvent);
BOOL bRet = WriteFile(dev->deviceHandle, reinterpret_cast<LPVOID>(buf), 11, &dwWrited, &ol);
if (bRet == FALSE)
{
DWORD dwTmp = 0;
GetOverlappedResult(dev->deviceHandle, &ol, &dwTmp, TRUE);
}

pTmp += nCurLen;
nBufSize -= nCurLen;
} while (nBufSize > 0);

if (ol.hEvent != NULL)
{
CloseHandle(ol.hEvent);
}
坑1:

传输大数据时,在有的电脑,会出现卡死情况

解决方式:

读跟写句柄分开创建,具体原因不明  

标签: c++ USB 设备读写

评论(0) 浏览(751)

MFC 函数注入

2019-11-22 C++

问题:

USB 通信DLL代码找不到,无法知道通信协议

解决思路:

注入windows相关接口,查看通信过程中发送的协议

实现代码:比如注入CreateFile

typedef HANDLE(WINAPI * Real_CreateFile) (
LPCWSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);

1. 保存函数调用地址

BYTE g_oldJmp[6] = { 0 };
BYTE g_jmp[6] = { 0 };

2. 实现注入函数 执行函数前先恢复原接口函数地址,执行完再设置为更改后的地址

HANDLE WINAPI Routed_CreateFile(
LPCWSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile)
{
CStringW strTmp(lpFileName);
HANDLE handle = NULL;
VirtualProtect((LPVOID)g_pOrigCreateFile, 6, g_myProtect, NULL); //ReadWrite again
memcpy(g_pOrigCreateFile, g_oldJmp, 6); //Unhook API
handle = CreateFileW(strTmp.GetString(), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
memcpy(g_pOrigCreateFile, g_jmp, 6); //Rehook API
VirtualProtect((LPVOID)g_pOrigCreateFile, 6, g_oldProtect, NULL); //Normal setts
CStringW strMsg(_T(""));
strMsg.Format(L"%s %x %x %x %x %x\r\n", strTmp.GetString(), dwDesiredAccess, dwShareMode, handle, dwCreationDisposition, dwFlagsAndAttributes);
::OutputDebugStringW(strMsg);
return handle;
}


//注入接口
void BeginRedirect(LPVOID newFunction, LPVOID oldFunction, BYTE *jmp, BYTE *oldJmp)
{
BYTE tempJMP[6] = {0xE9, 0x90, 0x90, 0x90, 0x90, 0xC3}; 
memcpy(jmp, tempJMP, 6);
DWORD dwJMPSize = (reinterpret_cast<DWORD>(newFunction) - reinterpret_cast<DWORD>(oldFunction) - 5);
VirtualProtect(oldFunction, 6, PAGE_EXECUTE_READWRITE, &g_oldProtect);
//Change memory settings to make sure we can write the JMP in
memcpy(oldJmp, oldFunction, 6); //Copy old bytes before writing JMP
memcpy(&jmp[1], &dwJMPSize, 4); //Write the address to JMP to
memcpy(oldFunction, jmp, 6); //Write it in process memory
VirtualProtect((LPVOID)oldFunction, 6, g_oldProtect, NULL); //Change 
}

//初始化

g_pOrigCreateFile = reinterpret_cast<Real_CreateFile>(GetProcAddress(GetModuleHandle("Kernel32.dll"), "CreateFileW")); 
if (g_pOrigCreateFile != NULL)
{
BeginRedirect(Routed_CreateFile, g_pOrigCreateFile, g_jmp, g_oldJmp);
}

标签: c++ 函数hook

评论(0) 浏览(338)

海康威视GB28181视频流接收解析显示

2019-3-1

海康威视国标GB28181获取视频流并显示

环境:

MFC,jRtp,ffmpeg,sdl2.0,eXosip,

海康威视摄像头:DS-2CD3T27EDWD-L

思路:

利用eXosip实现sip服务端及客户端,实现GB28181协议交互

利用jRtp接收摄像头rtp视频流

利用ffmpeg解码视频流(由于海康威视ps视频流里面含有一些私有协议会导致花屏,因此这边需要先把ps流解析成H264视频流)

利用sdl显示视频

标签: c++ ffmpeg rtp SDL

评论(0) 浏览(493)

利用dll生成lib

2018-4-29 C++

业务场景:

使用libvlc3.02 SDK提供的lib及dll编译运行程序,提示找不到XXX于动态链接库libvlc.dll上

解决办法:

直接利用libvlc.dll生成libvlc.lib

步骤:

dumpbin.exe:dll导出函数

C:\Program Files (x86)\Microsoft Visual Studio 8\VC\bin>dumpbin libvlc.dll /EXPORTS /OUT:libvlc.def

编辑libvlc.def只留下函数所在的行

          1    0 00002B30 libvlc_add_intf
          2    1 0000BB60 libvlc_audio_equalizer_get_amp_at_index
          3    2 0000B980 libvlc_audio_equalizer_get_band_count

python:格式化def

file = open(r"D:\Beihai\python\libvlco.def")
files = open(r"D:\Beihai\python\libvlc.def", "w")
fc = 1
while 1 :
    line = file.readline()
    if not line :
        break
    sl = line.split()
    #print sl[-1]
    nl = sl[-1] + " @ " + str(fc) + "\n"
    fc = fc + 1
    files.write(nl)
file.close()
files.close()

lib:利用def生成lib

lib /def:libvlc.def /MACHINE:IX86 /out:libvlc.lib



标签: python c++ def dll

评论(0) 浏览(1053)

c++面试

2017-9-6 C++

基础:

进程与线程的区别

写一个宏返回最小值

双向链表删除某个节点,插入节点

单链表反转

字符串反转

String构造类、操作符=重载

字符串循环右移

exe的文件头结构

虚构函数可以直接调用吗

构造函数初始化列表异常捕获

Makefile怎么编译一个文件

dll信息在exe头文件哪里

gdb调试bt有什么作用

算法:

    牛牛判断牛几算法

int grad(int *arr, int len)

{   

    for (int i = 0; i < len; i++)

    {   

        for (int j = 0; j < len; j++)

        {   

            for (int k = 0; k < len; k++)

            {   

                if (i !=j && i !=k && k != j)

                {   

                    if ((arr[i] + arr[j] + arr[k]) % 10 == 0)

                    {   

                        int sum = 0; 

                        for (int l = 0; l < len; l++)

                        {   

                            sum += arr[l];

                        }

                        return (sum - arr[i] - arr[j] - arr[k]) % 10;

                    }

                }

            }

        }

    }

    return -1;

}


    k个任务,每个任务有开始时间和结束时间,求24小时内最大执行任务数


    斗地主随机洗牌算法


Fisher–Yates shuffle 洗牌算法

void shuffle(int *arr, int len)

 {

    for (int i = len - 1; i >= 0; i--)

    {

        int randomIndex = rand() % (i + 1);

        int itemIndex = arr[randomIndex];

        arr[randomIndex] = arr[i];

        arr[i] = itemIndex;

    }

 }



使用:

    多线程无锁编程:

http://blog.csdn.net/zzulp/article/details/6259866


     send与write区别:


在功能上,read/write是recv/send的子集。read/wirte是更通用的文件描述符操作,而recv/send在socket领域则更“专业”一些。

当recv/send的flag参数设置为0时,则和read/write是一样的。

如果有如下几种需求,则read/write无法满足,必须使用recv/send:

  1. 为接收和发送进行一些选项设置
  2. 从多个客户端中接收报文
  3. 发送带外数据(out-of-band data)


标签: c++

评论(0) 浏览(1064)

Powered by EMLOG Copyright @ 狼酒 版权所有. 闽ICP备14012694号-2