windows USB 驅動開發-URB結構

通用串行總線 (USB) 客戶端驅動程序無法直接與其設備通信。 相反,客戶端驅動程序會創建請求并將其提交到 USB 驅動程序堆棧進行處理。 在每個請求中,客戶端驅動程序提供一個可變長度的數據結構,稱為 USB 請求塊 (URB) ,URB 結構描述請求的詳細信息,還包含有關已完成請求狀態的信息。 客戶端驅動程序通過 URL 執行所有特定于設備的操作,包括數據傳輸。 在將請求提交到 USB 驅動程序堆棧之前,客戶端驅動程序必須使用有關請求的信息初始化 URB。 對于某些類型的請求,Microsoft 提供幫助程序例程和宏,這些例程和宏分配 URB 結構,并使用客戶端驅動程序提供的詳細信息填充 URB 結構的必要成員。

每個 URB 都以標準固定大小的標頭開頭, (_URB_HEADER) ,其用途是標識請求的操作類型。 _URB_HEADER 的 Length 成員指定 URB 的大小(以字節為單位)。 Function 成員必須是一系列系統定義的URB_FUNCTION_XXX常量之一,用于確定所請求的操作類型。 例如,在數據傳輸的情況下,此成員指示傳輸的類型。 函數代碼URB_FUNCTION_CONTROL_TRANSFER、URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER和URB_FUNCTION_ISOCH_TRANSFER分別指示控制、批量/中斷和常時等量傳輸。 USB 驅動程序堆棧使用 Status 成員返回特定于 USB 的狀態代碼。

為了提交 URB,客戶端驅動程序使用 IOCTL_INTERNAL_USB_SUBMIT_URB 請求,該請求通過 I/O 請求數據包 (IRP) 類型IRP_MJ_INTERNAL_DEVICE_CONTROL傳遞到設備。

USB 驅動程序堆棧處理完 URB 后,驅動程序堆棧將使用 URB 結構的 Status 成員返回特定于 USB 的狀態代碼。

KMDF 和 UMDF 驅動程序開發人員應使用相應的框架接口來與 USB 設備通信。?

分配和構建 URB

USB 客戶端驅動程序可以使用 Windows 驅動程序模型 (WDM) 驅動程序例程來分配 URB 并格式化 URB,然后再將請求發送到 Microsoft 提供的 USB 驅動程序堆棧。

客戶端驅動程序使用 URB 打包 USB 驅動程序堆棧中較低級驅動程序處理請求所需的所有信息。 在 Windows 操作系統中,URB 在 URB 結構中描述。

Microsoft 為 USB 客戶端驅動程序提供了例程庫。 通過使用這些例程,USB 客戶端驅動程序可以為某些指定操作生成 URB 請求,并將其轉發到 USB 堆棧中。 如果愿意,可以將客戶端驅動程序設計為為支持的操作調用庫例程,而不是生成自己的 URB 請求。

Windows 7 及更早版本中的 URB 分配

若要使用適用于 Windows 7 及更早版本的 Windows 的 Windows 驅動程序工具包 (WDK) 中包含的例程發送 USB 請求,客戶端驅動程序通常會分配和填充 URB 結構,將 URB 結構與新的 IRP 相關聯,并將 IRP 發送到 USB 驅動程序堆棧。

對于某些類型的請求,Microsoft 提供 (由分配 URB 結構的Usbd.sys) 導出的幫助程序例程。 例如, USBD_CreateConfigurationRequestEx 例程為 URB 結構分配內存,為選擇配置請求設置 URB 格式,并將 URB 結構的地址返回到客戶端驅動程序。 但是,幫助程序例程不能用于所有類型的請求。

Microsoft 還提供了為某些類型的請求設置 URL 格式的宏。 對于這些宏,客戶端驅動程序必須通過調用 ExAllocatePoolWithTag 來分配 URB 結構,或者在堆棧上分配 結構。 例如,在客戶端驅動程序分配 URB 后,驅動程序可以調用 UsbBuildSelectConfigurationRequest 來格式化選擇配置請求的 URB 或清除配置。

對于其他請求,客戶端驅動程序必須根據請求類型,通過設置 URB 結構的各個成員來手動分配 和格式化 URB 。

USB 請求完成后,客戶端驅動程序必須釋放 URB 結構。 如果在堆棧上分配 URB,則 URB 在超出范圍時釋放。 如果在非分頁池中分配 URB,則客戶端驅動程序必須調用 ExFreePool 才能釋放 URB。

Windows 8中的 URB 分配

WDK for Windows 8 提供了一個新的靜態庫 Usbdex.lib,用于導出用于分配、格式化和釋放 URL 的例程。 此外,還有一種將 URB 與 IRP 相關聯的新方法。 新的例程可由面向 Windows Vista 和更高版本的 Windows 的客戶端驅動程序調用。

在 Windows Vista 及更高版本上運行的客戶端驅動程序必須使用新的例程,以便基礎 USB 驅動程序堆棧可以利用某些性能和可靠性改進。 這些改進適用于 Windows 8 中為支持 USB 3.0 設備和主機控制器而引入的新 USB 驅動程序堆棧。 對于 USB 2.0 主控制器,Windows 加載不支持改進的驅動程序堆棧的早期版本。 無論基礎驅動程序堆棧的版本或主機控制器支持的協議版本如何,都必須始終調用新的 URB 例程。

在調用任何新例程之前,請確保有一個 USBD 句柄,用于向 USB 驅動程序堆棧注冊客戶端驅動程序。 若要獲取 USBD 句柄, 請調用 USBD_CreateHandle。

WDK 提供以下例程,用于Windows 8。 這些例程在 Usbdlib.h 中定義。

  • USBD_UrbAllocate
  • USBD_IsochUrbAllocate
  • USBD_SelectConfigUrbAllocateAndBuild
  • USBD_SelectInterfaceUrbAllocateAndBuild
  • USBD_UrbFree
  • USBD_AssignUrbToIoStackLocation

前面列表中的分配例程返回指向由 USB 驅動程序堆棧分配的新 URB 結構的指針。 根據 Windows 加載的 USB 驅動程序堆棧的版本, URB 結構可以與不透明的 URB 上下文配對。 URB 上下文是有關 URB 的信息塊。 無法查看 URB 標頭的內容;這些信息旨在由 USB 驅動程序堆棧在內部使用,以改善 URB 跟蹤和處理。 URB 上下文僅由 USB 驅動程序堆棧用于Windows 8。 如果 URB 上下文可用,USB 驅動程序堆棧會使用它使 URB 處理更安全、更高效。 例如,USB 驅動程序堆棧必須確保客戶端驅動程序不會提交 URB,然后嘗試在第一個請求完成之前重復使用同一 URB。 為了檢測此類錯誤,USB 驅動程序堆棧會將狀態信息存儲在 URB 上下文中。 如果沒有狀態信息,USB 驅動程序堆棧將不得不將傳入的 URB 與當前正在進行的所有 URB 進行比較。 當客戶端驅動程序嘗試釋放 URB 時,USB 驅動程序堆棧也會使用狀態信息。 在釋放 URB 之前,USB 驅動程序堆棧會驗證狀態,以確保 URB 未掛起。

URB 上下文提供用于存儲額外 URB 信息的官方機制。 使用 URB 上下文比根據需要分配額外的內存或在 URB 結構的保留成員中存儲額外信息更可取。 USB 驅動程序堆棧在非分頁池中分配 URB 及其關聯的 URB 上下文,以便將來如果需要更大的 URB 上下文,唯一需要調整的是池分配的大小。

URB的結構
typedef struct _URB {union {
#if ..._URB_HEADER                                     UrbHeader;
#elsestruct _URB_HEADER                              UrbHeader;
#endif
#if ..._URB_SELECT_INTERFACE                           UrbSelectInterface;
#elsestruct _URB_SELECT_INTERFACE                    UrbSelectInterface;
#endif
#if ..._URB_SELECT_CONFIGURATION                       UrbSelectConfiguration;
#elsestruct _URB_SELECT_CONFIGURATION                UrbSelectConfiguration;
#endif
#if ..._URB_PIPE_REQUEST                               UrbPipeRequest;
#elsestruct _URB_PIPE_REQUEST                        UrbPipeRequest;
#endif
#if ..._URB_FRAME_LENGTH_CONTROL                       UrbFrameLengthControl;
#elsestruct _URB_FRAME_LENGTH_CONTROL                UrbFrameLengthControl;
#endif
#if ..._URB_GET_FRAME_LENGTH                           UrbGetFrameLength;
#elsestruct _URB_GET_FRAME_LENGTH                    UrbGetFrameLength;
#endif
#if ..._URB_SET_FRAME_LENGTH                           UrbSetFrameLength;
#elsestruct _URB_SET_FRAME_LENGTH                    UrbSetFrameLength;
#endif
#if ..._URB_GET_CURRENT_FRAME_NUMBER                   UrbGetCurrentFrameNumber;
#elsestruct _URB_GET_CURRENT_FRAME_NUMBER            UrbGetCurrentFrameNumber;
#endif
#if ..._URB_CONTROL_TRANSFER                           UrbControlTransfer;
#elsestruct _URB_CONTROL_TRANSFER                    UrbControlTransfer;
#endif
#if ..._URB_CONTROL_TRANSFER_EX                        UrbControlTransferEx;
#elsestruct _URB_CONTROL_TRANSFER_EX                 UrbControlTransferEx;
#endif
#if ..._URB_BULK_OR_INTERRUPT_TRANSFER                 UrbBulkOrInterruptTransfer;
#elsestruct _URB_BULK_OR_INTERRUPT_TRANSFER          UrbBulkOrInterruptTransfer;
#endif
#if ..._URB_ISOCH_TRANSFER                             UrbIsochronousTransfer;
#elsestruct _URB_ISOCH_TRANSFER                      UrbIsochronousTransfer;
#endif
#if ..._URB_CONTROL_DESCRIPTOR_REQUEST                 UrbControlDescriptorRequest;
#elsestruct _URB_CONTROL_DESCRIPTOR_REQUEST          UrbControlDescriptorRequest;
#endif
#if ..._URB_CONTROL_GET_STATUS_REQUEST                 UrbControlGetStatusRequest;
#elsestruct _URB_CONTROL_GET_STATUS_REQUEST          UrbControlGetStatusRequest;
#endif
#if ..._URB_CONTROL_FEATURE_REQUEST                    UrbControlFeatureRequest;
#elsestruct _URB_CONTROL_FEATURE_REQUEST             UrbControlFeatureRequest;
#endif
#if ..._URB_CONTROL_VENDOR_OR_CLASS_REQUEST            UrbControlVendorClassRequest;
#elsestruct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST     UrbControlVendorClassRequest;
#endif
#if ..._URB_CONTROL_GET_INTERFACE_REQUEST              UrbControlGetInterfaceRequest;
#elsestruct _URB_CONTROL_GET_INTERFACE_REQUEST       UrbControlGetInterfaceRequest;
#endif
#if ..._URB_CONTROL_GET_CONFIGURATION_REQUEST          UrbControlGetConfigurationRequest;
#elsestruct _URB_CONTROL_GET_CONFIGURATION_REQUEST   UrbControlGetConfigurationRequest;
#endif
#if ..._URB_OS_FEATURE_DESCRIPTOR_REQUEST              UrbOSFeatureDescriptorRequest;
#elsestruct _URB_OS_FEATURE_DESCRIPTOR_REQUEST       UrbOSFeatureDescriptorRequest;
#endif
#if ..._URB_OPEN_STATIC_STREAMS                        UrbOpenStaticStreams;
#elsestruct _URB_OPEN_STATIC_STREAMS                 UrbOpenStaticStreams;
#endif
#if ..._URB_GET_ISOCH_PIPE_TRANSFER_PATH_DELAYS        UrbGetIsochPipeTransferPathDelays;
#elsestruct _URB_GET_ISOCH_PIPE_TRANSFER_PATH_DELAYS UrbGetIsochPipeTransferPathDelays;
#endif};
} URB, *PURB;
URB 例程更新記錄

下表匯總了 URB 例程中的更改。

如何提交 URB

客戶端驅動程序使用 I/O 控制代碼 (IOCTL) IOCTL 與設備通信,這些請求在 I/O 請求數據包 (IRP) 類型為 IRP_MJ_INTERNAL_DEVICE_CONTROL。 對于特定于設備的請求(如選擇配置請求),與 IRP 關聯的 USB 請求塊 (URB) 中介紹了該請求。 將 URB 與 IRP 相關聯并將請求發送到 USB 驅動程序堆棧的過程稱為提交 URB。 若要提交 URB,客戶端驅動程序必須使用 IOCTL_INTERNAL_USB_SUBMIT_URB 作為設備控制代碼。 IOCTL 是提供 I/O 接口的“內部”控制代碼之一,客戶端驅動程序使用該接口來管理其設備和設備連接到的端口。 用戶模式應用程序無權訪問這些內部 I/O 接口。?

先決條件

在將請求發送到通用串行總線 (USB) 驅動程序堆棧之前,客戶端驅動程序必須根據請求的類型分配 URB 結構和格式,如下步驟:

  • 通過調用 IoAllocateIrp 例程為 URB 分配 IRP。 必須提供接收 IRP 的設備對象的堆棧大小。 在對 IoAttachDeviceToDeviceStack 例程的上一次調用中,你收到了指向該設備對象的指針。 堆棧大小存儲在 DEVICE_OBJECT 結構的 StackSize 成員中;
  • 通過調用 IoGetNextIrpStackLocation 獲取指向 IRP 的第一個堆棧位置 (IO_STACK_LOCATION) 的指針;
  • 將 IO_STACK_LOCATION 結構的 MajorFunction 成員設置為IRP_MJ_INTERNAL_DEVICE_CONTROL;
  • 將 IO_STACK_LOCATION 結構的 Parameters.DeviceIoControl.IoControlCode 成員設置為IOCTL_INTERNAL_USB_SUBMIT_URB;
  • 將 IO_STACK_LOCATION 結構的 Parameters.Others.Argument1 成員設置為初始化的 URB 結構的地址。 若要將 IRP 關聯到 URB,也可以僅當 URB 由 USBD_UrbAllocate、USBD_SelectConfigUrbAllocateAndBuild 或 USBD_SelectInterfaceUrbAllocateAndBuild 分配時才調用 USBD_AssignUrbToIoStackLocation;
  • 通過調用 IoSetCompletionRoutineEx 設置完成例程。如果異步提交 URB,請傳遞指向調用方實現的完成例程及其上下文的指針。 調用方在其完成例程中釋放 IRP。如果要同步提交 IRP,請實現一個完成例程,并在調用 IoSetCompletionRoutineEx 時傳遞指向該例程的指針。 調用還需要 Context 參數中的初始化 KEVENT 對象。 在完成例程中,將 事件設置為信號狀態;
  • 調用 IoCallDriver 將填充的 IRP 轉發到設備堆棧中的下一個下一個設備對象。 對于同步調用,在調用 IoCallDriver 后,通過調用 KeWaitForSingleObject 來等待事件對象以獲取事件通知;
  • 完成 IRP 后,檢查 IRP 的 IoStatus.Status 成員并評估結果。 如果 IoStatus.Status STATUS_SUCCESS,則表示請求成功;
USB 同步提交

以下示例演示如何同步提交 URB。

// The SubmitUrbSync routine submits an URB synchronously.
//
// Parameters:
//      DeviceExtension: Pointer to the caller's device extension. The
//                       device extension must have a pointer to
//                       the next lower device object in the device stacks.  
//
//      Irp: Pointer to an IRP allocated by the caller.
//
//      Urb: Pointer to an URB that is allocated by  USBD_UrbAllocate,
//           USBD_IsochUrbAllocate, USBD_SelectConfigUrbAllocateAndBuild,
//           or USBD_SelectInterfaceUrbAllocateAndBuild.//      CompletionRoutine: Completion routine.
//
// Return Value:
//
//      NTSTATUS  NTSTATUS SubmitUrbSync( PDEVICE_EXTENSION DeviceExtension,PIRP Irp,PURB Urb,  PIO_COMPLETION_ROUTINE SyncCompletionRoutine)  {NTSTATUS  ntStatus;  KEVENT    kEvent;PIO_STACK_LOCATION nextStack;// Get the next stack location.nextStack = IoGetNextIrpStackLocation(Irp);  // Set the major code.nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;  // Set the IOCTL code for URB submission.nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;  // Attach the URB to this IRP.// The URB must be allocated by USBD_UrbAllocate, USBD_IsochUrbAllocate,// USBD_SelectConfigUrbAllocateAndBuild, or USBD_SelectInterfaceUrbAllocateAndBuild.USBD_AssignUrbToIoStackLocation (DeviceExtension->UsbdHandle, nextStack, Urb);KeInitializeEvent(&kEvent, NotificationEvent, FALSE);ntStatus = IoSetCompletionRoutineEx ( DeviceExtension->NextDeviceObject,  Irp,  SyncCompletionRoutine,  (PVOID) &kEvent,  TRUE,TRUE,TRUE);if (!NT_SUCCESS(ntStatus)){KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "IoSetCompletionRoutineEx failed. \n" ));goto Exit;}ntStatus = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);  if (ntStatus == STATUS_PENDING){KeWaitForSingleObject ( &kEvent,Executive,KernelMode,FALSE,NULL);}ntStatus = Irp->IoStatus.Status;Exit:if (!NT_SUCCESS(ntStatus)){// We hit a failure condition,// We will free the IRPIoFreeIrp(Irp);Irp = NULL;}return ntStatus;
}// The SyncCompletionRoutine routine is the completion routine
// for the synchronous URB submit request.
//
// Parameters:
//
//      DeviceObject: Pointer to the device object.
//      Irp:          Pointer to an I/O Request Packet.
//      CompletionContext: Context for the completion routine.
//
// Return Value:
//
//      NTSTATUS  NTSTATUS SyncCompletionRoutine ( PDEVICE_OBJECT DeviceObject,PIRP           Irp,PVOID          Context)
{PKEVENT kevent;kevent = (PKEVENT) Context;if (Irp->PendingReturned == TRUE){KeSetEvent(kevent, IO_NO_INCREMENT, FALSE);}KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Request completed. \n" ));return STATUS_MORE_PROCESSING_REQUIRED;
}

USB 異步提交
以下示例演示如何異步提交 URB。

// The SubmitUrbASync routine submits an URB asynchronously.
//
// Parameters:
//
// Parameters:
//      DeviceExtension: Pointer to the caller's device extension. The
//                       device extension must have a pointer to
//                       the next lower device object in the device stacks.  
//
//      Irp: Pointer to an IRP allocated by the caller.
//
//      Urb: Pointer to an URB that is allocated by  USBD_UrbAllocate,
//           USBD_IsochUrbAllocate, USBD_SelectConfigUrbAllocateAndBuild,
//           or USBD_SelectInterfaceUrbAllocateAndBuild.//      CompletionRoutine: Completion routine.
//
//      CompletionContext: Context for the completion routine.
//
//
// Return Value:
//
//      NTSTATUSNTSTATUS SubmitUrbASync ( PDEVICE_EXTENSION DeviceExtension,PIRP Irp,PURB Urb,  PIO_COMPLETION_ROUTINE CompletionRoutine,  PVOID CompletionContext)  
{// Completion routine is required if the URB is submitted asynchronously.// The caller's completion routine releases the IRP when it completes.NTSTATUS ntStatus = -1;  PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);  // Attach the URB to this IRP.nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;  // Attach the URB to this IRP.nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;  // Attach the URB to this IRP.(void) USBD_AssignUrbToIoStackLocation (DeviceExtension->UsbdHandle, nextStack, Urb);  // Caller's completion routine will free the irp when it completes.ntStatus = IoSetCompletionRoutineEx ( DeviceExtension->NextDeviceObject,Irp,  CompletionRoutine,  CompletionContext,  TRUE,TRUE,TRUE);if (!NT_SUCCESS(ntStatus)){goto Exit;}(void) IoCallDriver(DeviceExtension->NextDeviceObject, Irp);Exit:if (!NT_SUCCESS(ntStatus)){// We hit a failure condition,// We will free the IRPIoFreeIrp(Irp);Irp = NULL;}return ntStatus;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/39033.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/39033.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/39033.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ctfshow-web入門-命令執行(web75-web77)

目錄 1、web75 2、web76 3、web77 1、web75 使用 glob 協議繞過 open_basedir&#xff0c;讀取根目錄下的文件&#xff0c;payload&#xff1a; c?><?php $anew DirectoryIterator("glob:///*"); foreach($a as $f) {echo($f->__toString(). ); } ex…

讀書筆記-Java并發編程的藝術-第3章(Java內存模型)-第9節(Java內存模型綜述)

3.9 Java內存模型綜述 前面對Java內存模型的基礎知識和內存模型的具體實現進行了說明。下面對Java內存模型的相關知識做一個總結。 3.9.1 處理器的內存模型 順序一致性內存模型是一個理論參考模型&#xff0c;JMM和處理器內存模型在設計時通常會以順序一致性內存模型為參照。…

ORB-SLAM2 安裝編譯運行(非 ROS)

安裝編譯 必備安裝工具 主要包括 cmake 、 git 、 gcc 、 g gcc 的全稱是 GNU Compiler Collection&#xff0c;它是由 GNU 推出的一款功能強大的、性能優越的 多平臺編譯器&#xff0c;是一個能夠編譯多種語言的編譯器。最開始 gcc 是作為 C 語言的編譯器&#xff08;GNU …

如何將等保2.0的要求融入日常安全運維實踐中?

等保2.0的基本要求 等保2.0是中國網絡安全領域的基本國策和基本制度&#xff0c;它要求網絡運營商按照網絡安全等級保護制度的要求&#xff0c;履行相關的安全保護義務。等保2.0的實施得到了《中華人民共和國網絡安全法》等法律法規的支持&#xff0c;要求相關行業和單位必須按…

C#/WPF 自制白板工具

隨著電子屏幕技術的發展&#xff0c;普通的黑板已不再適用現在的教學和演示環境&#xff0c;電子白板應運而生。本篇使用WPF開發了一個電子白板工具&#xff0c;功能豐富&#xff0c;非常使用日常免費使用&#xff0c;或者進行再次開發。 示例代碼如下&#xff1a; Stack<St…

拓撲排序[講課留檔]

拓撲排序 拓撲排序要解決的問題是給一個有向無環圖的所有節點排序。 即在 A O E AOE AOE網中找關鍵路徑。 前置芝士&#xff01; 有向圖&#xff1a;有向圖中的每一個邊都是有向邊&#xff0c;即其中的每一個元素都是有序二元組。在一條有向邊 ( u , v ) (u,v) (u,v)中&…

JavaScript 動態網頁實例 —— 廣告效果

廣告是現代網頁設計中不可或缺的內容。廣告可以有很多種形式,但最終目的都是要吸引觀眾的注意力。盡管廣告少不了畫面、音效和廣告語等效果,但其實現主要還是應用JavaScript 代碼,只要很好掌握了JavaScript程序設計,剩下的就是創意和美工了。本章介紹幾種廣告效果,包括對聯…

ChatGPT 官方發布桌面端,向所有用戶免費開放

Open AI 官方已經發布了適用于 macOS 的 ChatGPT 桌面端應用。 此前&#xff0c;該應用一直處于測試階段&#xff0c;僅 Plus 付費訂閱用戶可以使用。 目前已面向所有用戶開放&#xff0c;所有 Mac 用戶均可免費下載使用。 我們可以訪問官網下載安裝包&#xff1a;https://op…

Java利用poi實現word,excel,ppt,pdf等各類型文檔密碼檢測

介紹 最近工作上需要對word,excel,ppt,pdf等各類型文檔密碼檢測&#xff0c;對文件進行分類&#xff0c;有密碼的和沒密碼的做區分。查了一堆資料和GPT都不是很滿意&#xff0c;最后東拼西湊搞了個相對全面的檢測工具代碼類&#xff0c;希望能給需要的人帶來幫助。 說明 這段…

PHP 爬蟲之使用 Curl庫抓取淘寶商品列表數據網頁的方法

使用 PHP 的 cURL 庫來抓取淘寶商品列表數據網頁需要謹慎&#xff0c;因為淘寶等電商平臺通常會有反爬蟲機制&#xff0c;以防止數據被濫用。然而&#xff0c;如果你只是出于學習目的&#xff0c;并且了解并遵守了淘寶的robots.txt文件和相關的使用條款&#xff0c;你可以嘗試使…

2024 年江西省研究生數學建模競賽題目 B題投標中的競爭策略問題--完整思路、代碼結果分享(僅供學習)

招投標問題是企業運營過程中必須面對的基本問題之一。現有的招投標平臺有國家級的&#xff0c;也有地方性的。在招投標過程中&#xff0c;企業需要全面了解招標公告中的相關信息&#xff0c;在遵守招投標各種規范和制度的基礎上&#xff0c;選擇有效的競爭策略和技巧&#xff0…

基于JSP技術的校園餐廳管理系統

開頭語&#xff1a; 你好呀&#xff0c;我是計算機學長貓哥&#xff01;如果您對校園餐廳管理系統感興趣或有相關需求&#xff0c;歡迎隨時聯系我。我的聯系方式在文末&#xff0c;期待與您交流&#xff01; 開發語言&#xff1a;Java 數據庫&#xff1a;MySQL 技術&#x…

QT的編譯過程

qmake -project 用于從源代碼生成項目文件&#xff0c;qmake 用于從項目文件生成 Makefile&#xff0c;而 make 用于根據 Makefile 構建項目。 詳細解釋&#xff1a; qmake -project 這個命令用于從源代碼目錄生成一個初始的 Qt 項目文件&#xff08;.pro 文件&#xff09;。它…

Keil5中:出現:failed to execute ‘...\ARMCC\bin\ArmCC‘

點三個點&#xff0c;去自己的磁盤找自己的ARM\ARMCC\bin

深入解析:計算機系統總線全方位解讀

在計算機組成原理中&#xff0c;總線系統是連接計算機各個部件的重要通道。本文將詳細介紹系統總線的基本概念、分類、特性及性能指標、結構和控制方式。希望通過本文的講解&#xff0c;能夠幫助基礎小白更好地理解計算機系統總線的工作原理。 系統總線 (System Bus) 系統總線…

查看視頻時間基 time_base

時間基、codec, 分辨率&#xff0c;音頻和視頻的都一樣&#xff0c;才可以直接使用ffmpeg -f concat -i file.txt 方式合并。 On Thu, Dec 03, 2015 at 21:54:53 0200, redneb8888 wrote: I am looking for a way to find the time base of a stream (video or audio), $ ffpr…

selenium 簡介以及 selenium 環境配置

文章目錄 一、初識 selenium1.selenium 簡介2.selenium 三大組件3.selenium工作過程和原理4.selenium自動化測試流程5.selenium優點 二、自動化測試1.UI自動化本質2.UI自動化的前提3.適用場景4.UI自動化的原則5.UI自動化的覆蓋率 三、selenium 環境配置 一、初識 selenium 1.s…

單點登錄demo

gitee.com 搜索xxl(許雪里) 的sso 操作demo 完整流程圖

網絡安全控制相關技術

1.惡意代碼&#xff08;Malware&#xff09; 網絡從出現、發展演進都始終伴隨著安全方面的問題&#xff0c;只是每個階段表現的形式不同而已。在網絡安全方面&#xff0c;不能不提進行網絡攻擊的網絡病毒&#xff0c;或者說惡意代碼&#xff08;Malware&#xff09;。所有惡意…

MySQL中的網絡命名空間支持

Network Namespace Support&#xff08;網絡命名空間支持&#xff09; 提供了在Linux系統中創建和管理多個隔離網絡空間的能力。網絡命名空間是來自主機系統的網絡堆棧的邏輯副本。網絡命名空間對于設置容器或虛擬環境非常有用。每個名稱空間都有自己的IP地址、網絡接口、路由表…