亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關(guān)于我們
? 蟲蟲下載站

?? termsdriver.c

?? hid類usb對外設(shè)的驅(qū)動application
?? C
?? 第 1 頁 / 共 2 頁
字號:
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <basetyps.h>
#include <winioctl.h>
#include "hidsdi.h"
#include <setupapi.h>
#include <malloc.h>

#include "usbioctl.h"
#include "usbdesc.h"
#include "TermsDriver.h"

#define TermsDriver(foo) Java_TermsDriver_ ## foo

typedef struct _STRING_DESCRIPTOR_NODE
{
    struct _STRING_DESCRIPTOR_NODE *Next;
    UCHAR                           DescriptorIndex;
    USHORT                          LanguageID;
    USB_STRING_DESCRIPTOR           StringDescriptor[0];
} STRING_DESCRIPTOR_NODE, *PSTRING_DESCRIPTOR_NODE;

//------------讀寫事件,用于檢測超時時間內(nèi)的動作-----------
HANDLE ReadEventObject;
HANDLE WriteEventObject;
//---------------------------------------------------------

HANDLE TermsDriver(hcom)=NULL;

//---------------打印設(shè)備與HID設(shè)備的GUID-------------------
GUID DeviceGuid;
//---------------------------------------------------------

//---------------HID設(shè)備的能力描述符-----------------------
HIDP_CAPS Capabilities;
//---------------------------------------------------------

//---------------設(shè)備接口細(xì)節(jié)------------------------------
PSP_DEVICE_INTERFACE_DETAIL_DATA DetailData;
//---------------------------------------------------------

//---------------非阻塞讀寫標(biāo)志----------------------------
OVERLAPPED HIDOverlappedRead; 
OVERLAPPED HIDOverlappedWrite;
//---------------------------------------------------------

//---------------獲得HID設(shè)備能力---------------------------
void GetDeviceCapabilities(){
	PHIDP_PREPARSED_DATA PreparsedData;						//預(yù)解析數(shù)據(jù),裝載設(shè)備能力的描述
	HidD_GetPreparsedData(TermsDriver(hcom),&PreparsedData);
	HidP_GetCaps(PreparsedData,&Capabilities);				//將預(yù)解析數(shù)據(jù)填入設(shè)備能力描述符結(jié)構(gòu)體中
	HidD_FreePreparsedData(PreparsedData);					//釋放資源
}
//---------------------------------------------------------

//---------------HID設(shè)備傳輸有阻塞的可能,該函數(shù)為非阻塞模式傳輸定義事件------
void PreparedForOverlappedTransfer(){

    if(ReadEventObject==NULL){
		ReadEventObject=CreateEvent(NULL,TRUE,TRUE,"");
		HIDOverlappedRead.hEvent=ReadEventObject;
        HIDOverlappedRead.Offset=0;
		HIDOverlappedRead.OffsetHigh=0;
    }
	if(WriteEventObject==NULL){
		WriteEventObject=CreateEvent(NULL,TRUE,TRUE,"");
		HIDOverlappedWrite.hEvent=WriteEventObject;
        HIDOverlappedWrite.Offset=0;
		HIDOverlappedWrite.OffsetHigh=0;
    }
}

//----------------打印設(shè)備尋找字符串的私有函數(shù)--------------------------------

BOOL AreThereManufacturerStringDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDesc){
	if(DeviceDesc->iManufacturer)
		return TRUE;
	else
		return FALSE;
}

PUSB_STRING_DESCRIPTOR GetManufacturerStringDescriptor(HANDLE hUSBDevice,
						   unsigned long index,
						   PUSB_DEVICE_DESCRIPTOR DeviceDesc)

{

	//PSTRING_DESCRIPTOR_NODE supportedLanguagesString;
	//PSTRING_DESCRIPTOR_NODE stringDescNodeTail;

	unsigned char   DescriptorIndex=0x00;
    unsigned short  LanguageID=0;
	unsigned char   stringDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST)+
                             MAXIMUM_USB_STRING_LENGTH];
	BOOL success;
	unsigned long nBytes;
    unsigned long nBytesReturned;
	//unsigned long numLanguageIDs;
    //unsigned short *languageIDs;

	PUSB_DESCRIPTOR_REQUEST stringDescReq;
    PUSB_STRING_DESCRIPTOR  stringDesc;
    PSTRING_DESCRIPTOR_NODE stringDescNode;

    nBytes = sizeof(stringDescReqBuf);

    stringDescReq = (PUSB_DESCRIPTOR_REQUEST)stringDescReqBuf;
    stringDesc = (PUSB_STRING_DESCRIPTOR)(stringDescReq+1);
	DescriptorIndex=DeviceDesc->iManufacturer;

    // Zero fill the entire request structure
	//
    memset(stringDescReq, 0, nBytes);

	stringDescReq->ConnectionIndex = index;
	stringDescReq->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8)
                                        | DescriptorIndex;

    stringDescReq->SetupPacket.wIndex = LanguageID;

    stringDescReq->SetupPacket.wLength = (unsigned short)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));

	// Now issue the get descriptor request.
    //
    success = DeviceIoControl(hUSBDevice,
                              IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
                              stringDescReq,
                              nBytes,
                              stringDescReq,
                              nBytes,
                              &nBytesReturned,
                              NULL);
	if(!success)
	{
		return NULL;
	}

	if (nBytesReturned < 2)
    {
        return NULL;
    }

    if (stringDesc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE)
    {
        return NULL;
    }

    if (stringDesc->bLength != nBytesReturned - sizeof(USB_DESCRIPTOR_REQUEST))
    {
        return NULL;
    }

    if (stringDesc->bLength % 2 != 0)
    {
        return NULL;
    }

    //
    // Looks good, allocate some (zero filled) space for the string descriptor
    // node and copy the string descriptor to it.
    //

    stringDescNode = (PSTRING_DESCRIPTOR_NODE)malloc(sizeof(STRING_DESCRIPTOR_NODE) +
                                                    stringDesc->bLength);

    if (stringDescNode == NULL)
    {
        return NULL;
    }

    memcpy(stringDescNode->StringDescriptor,
           stringDesc,
           stringDesc->bLength);

	return stringDescNode->StringDescriptor;

	


}
void EnumerateDevice(HANDLE hUSBDevice,unsigned char buf[]){
	BOOL success;
	PUSB_NODE_CONNECTION_INFORMATION    connectionInfo;
    //PUSB_DESCRIPTOR_REQUEST             configDesc;
    PUSB_STRING_DESCRIPTOR             stringDescs;
	unsigned long nBytes;

	nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION) +
                 sizeof(USB_PIPE_INFO) * 30;

	connectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)malloc(nBytes);
	if(connectionInfo==NULL){
	}
	else{
		connectionInfo->ConnectionIndex = 0;

		success = DeviceIoControl(hUSBDevice,
                              IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
                              connectionInfo,
                              nBytes,
                              connectionInfo,
                              nBytes,
                              &nBytes,
                              NULL);

		if (AreThereManufacturerStringDescriptor(&connectionInfo->DeviceDescriptor)){
			stringDescs = GetManufacturerStringDescriptor(
                          hUSBDevice,
                          0,
                          &connectionInfo->DeviceDescriptor);
			//buf=stringDescs->bString[0];
			memcpy(buf,stringDescs->bString[0],sizeof(stringDescs->bString[0]));
			free(connectionInfo);
		}
	}
}

//----------------------------------------------------------------------------

//----------------當(dāng)printFlag為TRUE時尋找打印設(shè)備,否則尋找HID類設(shè)備----------
//----------------找尋設(shè)備一共分為8步-----------------------------------------

//	1、獲取對應(yīng)的USB類設(shè)備的GUID
//	2、獲得擁有該GUID類的設(shè)備的集合
//	3、遍歷設(shè)備集合里每一個設(shè)備的接口標(biāo)識
//	4、獲取每一個標(biāo)識下接口的詳細(xì)數(shù)據(jù)結(jié)構(gòu)
//	5、獲取設(shè)備路徑,打開設(shè)備
//	6、獲得設(shè)備的字符串描述符
//	7、與既定規(guī)則進行比較
//	8、如果不符合,關(guān)閉設(shè)備,繼續(xù)尋找;如果符合,繼續(xù)操作。
//---------------------------------------------------------------------------

BOOL SearchDevices(byte deviceType[],BOOL printFlag){
	HIDD_ATTRIBUTES attributes;
	BOOL LastDevice=FALSE;
	BOOL DeviceDetected=FALSE;
	long Required;
	HANDLE hDevInfo;
	SP_DEVICE_INTERFACE_DATA DevInfoData;
	int Length,i,MemberIndex,Result;
	unsigned char tmpStr[128];
	unsigned char str[64];
	unsigned char str1[10];

	memset(tmpStr,0x00,128);
	memset(str,0x00,64);
	memset(str1,0x00,10);

	if(printFlag==TRUE){
		printf("1 haha!\n");

		//--------獲取Print類設(shè)備的GUID---------
		DeviceGuid.Data1 = 0x28d78fad;
		DeviceGuid.Data2 = 0x5a12;
		DeviceGuid.Data3 = 0x11D1;
		DeviceGuid.Data4[0] = 0xae;
		DeviceGuid.Data4[1] = 0x5b;
		DeviceGuid.Data4[2] = 0x00;
		DeviceGuid.Data4[3] = 0x00;
		DeviceGuid.Data4[4] = 0xf8;
		DeviceGuid.Data4[5] = 0x03;
		DeviceGuid.Data4[6] = 0xa8;
		DeviceGuid.Data4[7] = 0xc2;
		//--------------------------------------
/*
		//-------獲取Print蕾設(shè)備的GUID2---------
		DeviceGuid.Data1 = 0x36FC9E60;
		DeviceGuid.Data2 = 0xC465;
		DeviceGuid.Data3 = 0x11CF;
		DeviceGuid.Data4[0] = 0x80;
		DeviceGuid.Data4[1] = 0x56;
		DeviceGuid.Data4[2] = 0x44;
		DeviceGuid.Data4[3] = 0x45;
		DeviceGuid.Data4[4] = 0x53;
		DeviceGuid.Data4[5] = 0x54;
		DeviceGuid.Data4[6] = 0x00;
		DeviceGuid.Data4[7] = 0x00;
		//--------------------------------------
*/
		//-------獲得指定類的設(shè)備集合-----------
		hDevInfo=SetupDiGetClassDevs(&DeviceGuid,NULL,NULL,DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);
		//--------------------------------------

		DevInfoData.cbSize=sizeof(DevInfoData);
		MemberIndex=0;
		LastDevice=FALSE;

		//-------遍歷該類下每一個設(shè)備-----------
		do{
			//---獲取設(shè)備的標(biāo)識結(jié)構(gòu)-------------
			Result=SetupDiEnumDeviceInterfaces(hDevInfo,
				0,
				&DeviceGuid,
				MemberIndex,
				&DevInfoData);

			if(Result!=0){

				//---獲得用于分配PSP_DEVICE_INTERFACE_DETAIL_DATA的空間的長度---
				Result=SetupDiGetDeviceInterfaceDetail(hDevInfo,
					&DevInfoData,
					NULL,
					0,
					&Length,
					NULL);

				//---獲得接口的詳細(xì)數(shù)據(jù)結(jié)構(gòu)---
				DetailData=(PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(Length);
				DetailData->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
				Result=SetupDiGetDeviceInterfaceDetail(hDevInfo,
					&DevInfoData,
					DetailData,
					Length,
					&Required,
					NULL);

				printf("path is %s\n",DetailData->DevicePath);

				//----獲取設(shè)備路徑,以非獨占、非阻塞方式打開設(shè)備----
				//----以非阻塞方式打開USB口設(shè)備-------------------
				
				TermsDriver(hcom)=CreateFile(DetailData->DevicePath,
					GENERIC_READ|GENERIC_WRITE,
					FILE_SHARE_READ|FILE_SHARE_WRITE,
					NULL,
					OPEN_EXISTING,
					FILE_FLAG_OVERLAPPED,
					NULL);
/*
				//-----獲得廠商字符串,然后進行比較-----
				//HidD_GetManufacturerString(TermsDriver(hcom),
				//		tmpStr,
				//		128);
				EnumerateDevice(TermsDriver(hcom),tmpStr);

				//-----將Unicode編碼轉(zhuǎn)化為ASCII碼-------
				for(i=0;i<64;i++){
					str[i]=tmpStr[2*i];
				}
				//--------------------------------------
				str1[0]=str[12];// I
				str1[1]=str[13];// C
				str1[2]=str[14];// B
				str1[3]=str[15];// C

				//----------------比較細(xì)則--------------
				if(strcmp(deviceType,"pr2")==0||strcmp(deviceType,"Ar2400")==0){
					str1[4]=str[16];
					if(strcmp(str1,"ICBC1")==0||strcmp(str1,"ICBC0")==0){
						DeviceDetected=TRUE;
						PreparedForOverlappedTransfer();
					}
				}else{ 
					if(strcmp(deviceType,"scanner")==0){
						str1[4]=str[16];
						if(strcmp(str1,"ICBC2")==0){
							DeviceDetected=TRUE;
							PreparedForOverlappedTransfer();
						}else{ 
							if(strcmp(str1,"ICBC0")==0){
								str1[5]=str[17];
								if(strcmp(str1,"ICBC01")==0){
									DeviceDetected=TRUE;
									PreparedForOverlappedTransfer();
								}else{
									//CloseHandle(TermsDriver(hcom));
								}
							}else {
								//CloseHandle(TermsDriver(hcom));
							}
						}
					}
				}
				//--------------------------------------------------
*/
				DeviceDetected=TRUE;
				LastDevice=TRUE;
				PreparedForOverlappedTransfer();
			free(DetailData);
			}else
				LastDevice=TRUE;
			MemberIndex=MemberIndex+1;
		}while(LastDevice!=TRUE&&DeviceDetected!=TRUE);
		
		SetupDiDestroyDeviceInfoList(hDevInfo);
		return DeviceDetected;
	}else{
		//------------------尋找HID類設(shè)備--------------------
		memset(tmpStr,0x00,128);//廠商Unicode編碼的字符串
		memset(str,0x00,64);//廠商Unicode編碼高位編碼
		memset(str1,0x00,10);
		LastDevice=FALSE;
		DeviceDetected=FALSE;
		MemberIndex=0;
		Result=0;
		Length=0;
		i=0;

		TermsDriver(hcom)=NULL;

		//獲得HID類型設(shè)備的Guid
		HidD_GetHidGuid(&DeviceGuid);

		hDevInfo=SetupDiGetClassDevs(&DeviceGuid,NULL,NULL,DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
		DevInfoData.cbSize=sizeof(DevInfoData);
		do
		{
			Result=SetupDiEnumDeviceInterfaces(hDevInfo,
				0,
				&DeviceGuid,
				MemberIndex,
			    &DevInfoData);
			if(Result!=0){
				Result=SetupDiGetDeviceInterfaceDetail(hDevInfo,
					&DevInfoData,
					NULL,
					0,
					&Length,
					NULL);

				DetailData=(PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(Length);
				DetailData->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

				Result=SetupDiGetDeviceInterfaceDetail(hDevInfo,
					&DevInfoData,
					DetailData,
					Length,
					&Required,
					NULL);

				TermsDriver(hcom)=CreateFile(DetailData->DevicePath,
					GENERIC_READ|GENERIC_WRITE,
					FILE_SHARE_READ|FILE_SHARE_WRITE,
					NULL,
					OPEN_EXISTING,
					FILE_FLAG_OVERLAPPED,
					NULL);
				attributes.Size=sizeof(attributes);
				DeviceDetected=FALSE;

				Result=HidD_GetAttributes(TermsDriver(hcom),&attributes);
				HidD_GetManufacturerString(TermsDriver(hcom),
					tmpStr,
					128);
				for(i=0;i<64;i++){
					str[i]=tmpStr[2*i];
				}
				str1[0]=str[12];
				str1[1]=str[13];
				str1[2]=str[14];
				str1[3]=str[15];
				if(strcmp(deviceType,"PinKey")==0){
					str1[4]=str[16];

					if(strcmp(str1,"ICBC1")==0){
						DeviceDetected=TRUE;
					    GetDeviceCapabilities();
					    PreparedForOverlappedTransfer();
					}
					else 
						if(strcmp(str1,"ICBC0")==0){
							str1[5]=str[17];
							if(strcmp(str1,"ICBC01")==0){
								DeviceDetected=TRUE;
								GetDeviceCapabilities();
								PreparedForOverlappedTransfer();
							}else{
								//CloseHandle(TermsDriver(hcom));
							}
						}
				}
				if(strcmp(deviceType,"MSFDriver")==0){
					str1[4]=str[16];
					if(strcmp(str1,"ICBC2")==0){
						DeviceDetected=TRUE;
					    GetDeviceCapabilities();
					    PreparedForOverlappedTransfer();
					}
					else 

?? 快捷鍵說明

復(fù)制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
一区二区三区**美女毛片| 日本不卡在线视频| 4438x成人网最大色成网站| 国产精品一区二区在线观看网站 | 精品一区二区三区影院在线午夜| 国产精品久久毛片av大全日韩| 日韩一级大片在线| 国产资源精品在线观看| 国产精品一区二区果冻传媒| 日本不卡高清视频| 亚洲成年人影院| 亚洲女同ⅹxx女同tv| 国产亚洲女人久久久久毛片| 日韩欧美国产一区二区三区| 成人av在线播放网站| 久久99国产精品免费| 午夜精品免费在线| 欧美一级在线视频| 在线欧美一区二区| 欧美性色黄大片| 99久久国产综合精品女不卡| 国产成人综合在线播放| 老司机精品视频线观看86| 亚洲一区二区三区三| 日本一区二区视频在线观看| 一区二区三区在线观看动漫| 亚洲第一综合色| 亚洲一区二区视频| 亚洲综合小说图片| 日韩制服丝袜av| 另类欧美日韩国产在线| 国产精品自拍av| 成人午夜又粗又硬又大| 成人精品在线视频观看| 国产91丝袜在线播放0| 国产成人综合亚洲网站| 成人av电影在线网| www.av亚洲| 91精品国产麻豆国产自产在线| 欧美精品乱码久久久久久按摩| 欧美大片在线观看一区二区| 亚洲精品一区在线观看| 日韩理论片网站| 亚洲成av人片在线| 麻豆91精品视频| 极品销魂美女一区二区三区| 国产成人免费视| 91蜜桃婷婷狠狠久久综合9色| 成人app下载| 一本到一区二区三区| 欧洲人成人精品| 精品久久国产字幕高潮| 中文字幕一区二区三| 亚洲高清中文字幕| 国产1区2区3区精品美女| 91亚洲国产成人精品一区二区三 | 久久国产精品露脸对白| 国产精品亚洲视频| 欧美日韩精品免费| 91久久久免费一区二区| 日韩一级大片在线| 日本vs亚洲vs韩国一区三区二区 | 国产一区二区中文字幕| 99麻豆久久久国产精品免费| 欧美日韩午夜精品| 国产欧美日韩综合精品一区二区 | 日韩在线一区二区| 久久精品国产亚洲一区二区三区| 成人免费毛片app| 91麻豆精品国产91久久久使用方法| 91精品蜜臀在线一区尤物| 精品国产乱码久久久久久老虎| 亚洲影院在线观看| 国产不卡在线视频| 欧美精品国产精品| 国产精品福利一区| 国产一区二区在线电影| 国产91丝袜在线观看| 欧美日韩视频一区二区| 久久久99久久| 色又黄又爽网站www久久| 欧美国产综合色视频| 蜜臀久久99精品久久久久久9 | 国产亚洲美州欧州综合国| 午夜精品福利一区二区三区av | 日本欧美久久久久免费播放网| 99精品久久久久久| 久久综合九色综合97婷婷| 亚洲精品一区二区精华| 国产麻豆9l精品三级站| 日韩精品自拍偷拍| 日韩经典一区二区| 在线视频观看一区| 国产日韩欧美综合在线| 久久99九九99精品| 色婷婷综合激情| 91精品欧美综合在线观看最新| 亚洲精品国产视频| 波多野结衣精品在线| 精品国产乱码久久久久久久久 | 99在线热播精品免费| 欧美日本一区二区| 午夜电影久久久| 欧美绝品在线观看成人午夜影视| 亚洲成人综合在线| 91日韩精品一区| 亚洲色图另类专区| 99久久99久久精品免费看蜜桃| 午夜激情久久久| 欧美男人的天堂一二区| 日本三级亚洲精品| 欧美成人一区二区三区片免费 | 久久久久久久久久久久电影| 日本va欧美va欧美va精品| 精品国产一区二区三区四区四| 美女网站视频久久| 亚洲一区二区影院| 国产午夜精品久久| 波多野结衣精品在线| 亚洲一线二线三线视频| 欧美精品一级二级| 日本在线不卡视频| 欧美日韩精品免费| av在线不卡电影| 亚洲va韩国va欧美va精品| 欧美成人一区二区三区片免费| 国产suv精品一区二区6| 国产精品国产三级国产aⅴ中文| 91免费国产视频网站| 日韩电影在线免费观看| 国产三级欧美三级日产三级99 | 久久综合九色综合欧美就去吻| 成人av午夜电影| 欧美aaaaaa午夜精品| 中文字幕在线一区二区三区| 欧美日韩情趣电影| 粗大黑人巨茎大战欧美成人| 综合久久综合久久| 日韩欧美视频在线| 色综合视频在线观看| 麻豆成人av在线| 亚洲h在线观看| 欧美色中文字幕| 成人精品免费看| 久草在线在线精品观看| 欧美三级午夜理伦三级中视频| 国产自产高清不卡| 欧美国产成人精品| 欧美韩国日本一区| 91精品国产欧美一区二区| av午夜一区麻豆| 久久国产精品免费| 一区二区欧美视频| 日本一区二区三区免费乱视频| 欧美精品乱码久久久久久按摩| 91麻豆精品在线观看| 久久66热偷产精品| 五月婷婷欧美视频| 亚洲小说欧美激情另类| 国产精品久久久久久久久动漫| 欧美一区二区精品在线| 风间由美一区二区av101| 成人禁用看黄a在线| 老色鬼精品视频在线观看播放| 亚洲免费电影在线| 国产精品人成在线观看免费 | 日本不卡免费在线视频| 一区二区三区成人| 日韩毛片在线免费观看| 中文字幕一区免费在线观看| 国产欧美日产一区| 精品福利视频一区二区三区| 在线不卡免费av| 精品视频在线免费| 丝瓜av网站精品一区二区| 亚洲高清免费观看 | 色综合婷婷久久| 国产精品主播直播| 成人午夜免费av| 国模一区二区三区白浆| 久久国产精品99精品国产| 日韩和欧美一区二区| 一区二区三区在线观看国产 | 中文字幕亚洲电影| 99久久综合99久久综合网站| 99热这里都是精品| 92精品国产成人观看免费 | 精品国产乱码久久久久久图片| 中文字幕亚洲区| 亚洲午夜电影网| 粉嫩在线一区二区三区视频| 欧美二区三区的天堂| 国产精品福利一区| 精品中文字幕一区二区小辣椒| 91在线小视频| 久久香蕉国产线看观看99| 天堂va蜜桃一区二区三区漫画版 | 国产精品护士白丝一区av| 偷窥国产亚洲免费视频| 91视频91自|