每日看点!用VC6.0怎么实现上位机串口通信?位机串口通信的设置方法
串口是常用的计算机与外部串行设备之间的数据传输通道,由于串行通信方便易行,所以应用广泛。我们可以利用Windows API 提供的通信函数编写出高可移植性的串行通信程序。本实例介绍在Visual C++6.0下如何利用Win32 API 实现串行通信程序。程序编译运行后的界面效果如图一所示:
【资料图】
一、实现方法在Win16中,可以利用OpenComm()、CloseComm()和WriteComm()等函数打开、关闭和读写串口。但在Win32中,串口和其他通信设备均被作为文件处理,串口的打开、关闭和读写等操作所用的API函数与操作文件的函数相同。可通过CreateFile()函数打开串口;通过CloseFile()函数关闭串口;通过DCB结构、CommProp()、GetCommProperties()、SetCommProperties()、GetCommState()及SetCommState()等函数设置串口状态,通过函数ReadFile()和WritFile()等函数读写串口。下面来详细介绍其实现原理。
对于串行通信设备,Win32 API支持同步和异步两种I/O操作。同步操作方式的程序设计相对比较简单,但I/O操作函数在I/O操作结束前不能返回,这将挂起调用线程,直到I/O操作结束。异步操作方式相对要复杂一些,但它可让耗时的I/O操作在后台进行,不会挂起调用线程,这在大数据量通信的情况下对改善调用线程的响应速度是相当有效的。异步操作方式特别适合同时对多个串行设备进行I/O操作和同时对一个串行设备进行读/写操作。
串行设备的初始化
串行设备的初始化是利用CreateFile()函数实现的。该函数获得串行设备句柄并对其进行通信参数设置,包括设置输出/接收缓冲区大小、超时控制和事件监视等。 例如下面的代码实现了串口的初始化:
//串行设备句柄; HANDLE hComDev=0; //串口打开标志; BOOL bOpen=FALSE; //线程同步事件句柄; HANDLE hEvent=0; DCB dcb; COMMTIMEOUTS timeouts; //设备已打开 if(bOpen) return FALSE; //打开COM1 if((hComDev=CreateFile(“COM1”,GENERICREAD|GENERICWRITE,0,NULL,OPENEXISTING,FILEATTRIBUTENORMAL,NULL))==INVALIDHANDLEVALUE)
return FALSE; //设置超时控制 SetCommTimeouts(hComDev,&timeouts); //设置接收缓冲区和输出缓冲区的大小 SetupComm(hComDev,1024,512); //获取缺省的DCB结构的值 GetCommState(hComDev,&dcb); //设定波特率为9600 bps dcb.BaudRate=CBR9600; //设定无奇偶校验 dcb.fParity=NOPARITY; //设定数据位为8 dcb.ByteSize=8; //设定一个停止位 dcb.StopBits=ONESTOPBIT; //监视串口的错误和接收到字符两种事件 SetCommMask(hComDev,EVERR|EVRXCHAR); //设置串行设备控制参数 SetCommState(hComDev,&dcb); //设备已打开 bOpen=TRUE; //创建人工重设、未发信号的事件 hEvent=CreateEvent(NULL,FALSE,FALSE, “WatchEvent”); //创建一个事件监视线程来监视串口事件 AfxBeginThread(CommWatchProc,pParam); }
在设置串口DCB结构的参数时,不必设置每一个值。首先读出DCB缺省的参数设置,然后只修改必要的参数,其他参数都取缺省值。由于对串口进行的是同步I/O操作,所以除非指定进行监测的事件发生,否则WaitCommEvent()函数不会返回。在串行设备初始化的最后要建立一个单独的监视线程来监视串口事件,以免挂起当前调用线程,其中pParam可以是一个对事件进行处理的窗口类指针。
如果要进行异步I/O操作,打开设备句柄时,CreateFile的第6个参数应增加FILEFLAGOVERLAPPED 标志。
数据发送
数据发送利用WriteFile()函数实现。对于同步I/O操作,它的最后一个参数可为NULL;而对异步I/O操作,它的最后一个参数必需是一个指向OVERLAPPED结构的指针,通过OVERLAPPED结构来获得当前的操作状态。
BOOL WriteComm(LPCVOID lpSndBuffer,DWORD dwBytesToWrite) { //lpSndBuffer为发送数据缓冲区指针, dwBytesToWrite为将要发送的字节长度 //设备已打开 BOOL bWriteState; //实际发送的字节数 DWORD dwBytesWritten; //设备未打开 if(!bOpen) return FALSE; bWriteState=WriteFile(hComDev,lpSndBuffer,dwBytesToWrite,&dwBytesWritten,NULL); if(!bWriteState || dwBytesToWrite!=dwBytesWritten)
//发送失败
return FALSE; else
//发送成功
return TRUE; }
数据接收
接收数据的任务由ReadFile函数完成。该函数从串口接收缓冲区中读取数据,读取数据前,先用ClearCommError函数获得接收缓冲区中的字节数。接收数据时,同步和异步读取的差别同发送数据是一样的。
DWORD ReadComm(LPVOID lpInBuffer,DWORD dwBytesToRead) { //lpInBuffer为接收数据的缓冲区指针, dwBytesToRead为准备读取的数据长度(字节数) //串行设备状态结构 COMSTAT ComStat; DWORD dwBytesRead,dwErrorFlags; //设备未打开 if(!bOpen) return 0; //读取串行设备的当前状态 ClearCommError(hComDev,&dwErrorFlags,&ComStat); //应该读取的数据长度 dwBytesRead=min(dwBytesToRead,ComStat.cbInQue); if(dwBytesRead>0)
//读取数据
if(!ReadFile(hComDev,lpInBuffer,dwBytesRead,&dwBytesRead,NULL))
dwBytesRead=0; return dwBytesRead; }
事件监视线程
事件监视线程对串口事件进行监视,当监视的事件发生时,监视线程可将这个事件发送(SendMessage)或登记(PostMessage)到对事件进行处理的窗口类(由pParam指定)中。
UINT CommWatchProc(LPVOID pParam) { DWORD dwEventMask=0; //发生的事件; while(bOpen) {
//等待监视的事件发生
WaitCommEvent(hComDev, &dwEventMask,NULL);
if ((dwEventMask & EVRXCHAR)==EVRXCHAR)
……//接收到字符事件后,可以将此消息登记到由pParam有指定的窗口类中进行处理
if(dwEventMask & EVERR)==EVERROR)
……//发生错误时的处理 } SetEvent(hEvent); //发信号,指示监视线程结束 return 0; }
关闭串行设备
在整个应用程序结束或不再使用串行设备时,应将串行设备关闭,包括取消事件监视,将设备打开标志bOpen置为FALSE以使事件监视线程结束,清除发送/接收缓冲区和关闭设备句柄。
void CloseSynComm() { if(!bOpen) return; //结束事件监视线程 bOpen=FALSE; SetCommMask(hComDev,0); //取消事件监视,此时监视线程中的WaitCommEvent将返回 WaitForSingleObject(hEvent,INFINITE); //等待监视线程结束 CloseHandle(hEvent); //关闭事件句柄 //停止发送和接收数据,并清除发送和接收缓冲区 PurgeComm(hComDev,PURGETXABORT| PURGERXABORT|PURGETXCLEAR|PURGERXCLEAR); //关闭设备句柄 CloseHandle(hComDev); }
二、编程步骤1、 启动Visual C++6.0,生成一个基于对话框的的应用程序,将该程序命名为“SerealCom”;
2、 按照图一的界面设计对话框,具体设置参见代码部分;
3、 使用Class Wizard为对话框的按钮添加鼠标单击消息响应函数;
4、 添加代码,编译运行程序。
1 #if !defined(_COMM_ACCESS_FUNCTIONS_AND_DATA) 2 #define _COMM_ACCESS_FUNCTIONS_AND_DATA 3 #if _MSC_VER > 1000 4 #pragma once 5 #endif // _MSC_VER > 1000 6 #define EVENTCHAR 0x0d 7 #define MAXBLOCKLENGTH 59 8 9 extern BYTE XwCom; 10 extern BYTE sCom1[5],sCom2[MAXBLOCKLENGTH+12]; 11 extern sCom3[MAXBLOCKLENGTH+12]; 12 extern BYTE opation; 13 extern short ComNum; 14 15 #define FC_DTRDSR 0x01 16 #define FC_RTSCTS 0x02 17 #define FC_XONXOFF 0x04 18 #define ASCII_BEL 0x07 19 #define ASCII_BS 0x08 20 #define ASCII_LF 0x0A 21 #define ASCII_CR 0x0D 22 #define ASCII_XON 0x11 23 #define ASCII_XOFF 0x13 24 25 class CComStatus 26 { 27 public: 28
HANDLE m_hCom; 29
BYTE m_bComId; 30
BYTE m_bByteSize; 31
BYTE m_bStopBits; 32
BYTE m_bParity; 33
DWORD m_dwBaudRate; 34 35
//WORD m_fChEvt; 36 37
char m_bEvtChar; 38
DWORD m_fBinary; 39
BOOL m_bConnected; 40
BOOL m_fXonXoff; 41
BOOL m_bFlowCtrl; 42
OVERLAPPED m_rdos; 43
OVERLAPPED m_wtos; 44 45
//functions 46 47
CComStatus(); 48
CComStatus(BYTE bComId,BYTE bByteSize,BYTE bStopBits,BYTE bParity, 49
DWORD dwBaudRate,/*WORD fChEvt,*/char bEvtChar,DWORD fBinary); 50
BOOL OpenConnection(); 51
BOOL CloseConnection(); 52
BOOL SetupConnection(); 53
BOOL IsConnected(); 54 }; 55 56 UINT CommWatchProc( LPVOID lpData ); 57 BOOL WriteCommBlock( CComStatus& comDev, LPSTR lpByte , DWORD dwBytesToWrite); 58 int ReadCommBlock(CComStatus& comDev,LPSTR lpszBlock, int nMaxLength ); 59 int ReadCommBlockEx(CComStatus& comDev,LPSTR lpszBlock, int nMaxLength,DWORD dwTimeOut); 60 #endif 61 62 /// 63 64 #include "stdafx.h" 65 #include "com232.h" 66 67 BYTE XwCom=0x40; 68 BYTE sCom1[5],sCom2[MAXBLOCKLENGTH+12],sCom3[MAXBLOCKLENGTH+12]; 69 BYTE opation; 70 short ComNum; 71 CComStatus::CComStatus() 72 { 73 m_hCom = NULL; 74 m_bComId = (char)ComNum;//COM1 75 m_bByteSize=8; 76 m_bStopBits=ONESTOPBIT; 77 m_bParity=NOPARITY; 78 m_dwBaudRate=9600; 79 m_bEvtChar=EVENTCHAR; 80 m_fBinary=1; 81 m_bConnected = FALSE; 82 m_bFlowCtrl = FC_XONXOFF ; 83 m_fXonXoff = FALSE; 84 } 85 86 CComStatus::CComStatus(BYTE bComId,BYTE bByteSize,BYTE bStopBits,BYTE bParity,DWORD dwBaudRate,/*WORD fChEvt,*/char bEvtChar,DWORD fBinary) 87 { 88 m_hCom = NULL; 89 m_bComId = bComId; 90 m_bByteSize=bByteSize; 91 m_bStopBits=bStopBits; 92 m_bParity=bParity; 93 m_dwBaudRate=dwBaudRate; 94 m_bEvtChar=bEvtChar; 95 m_fBinary=fBinary; 96 m_bConnected = FALSE; 97 m_bFlowCtrl = FC_XONXOFF ; 98 m_fXonXoff = FALSE; 99 }100 101 BOOL CComStatus::OpenConnection()102 {103 char csCom[10];104 COMMTIMEOUTS CommTimeOuts ;105 if((m_bComId < 0) || (m_bComId > 4))106
return FALSE;//从COM1到COM4107 if(m_hCom)//if already open108 return FALSE;109 110 //OVERLAPPED包含异步I/O信息111 112 m_rdos.Offset = 0;113 m_rdos.OffsetHigh = 0;114 m_rdos.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);115 if(m_rdos.hEvent == NULL)116
return FALSE;117 m_wtos.Offset = 0;118 m_wtos.OffsetHigh = 0;119 m_wtos.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);120 if(m_wtos.hEvent == NULL)121 {122
CloseHandle(m_rdos.hEvent);123
return FALSE;124 }125 126 wsprintf(csCom,"COM%d",m_bComId);127 128 m_hCom = CreateFile(csCom,GENERIC_READ | GENERIC_WRITE, 0,NULL, OPEN_EXISTING,ILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,NULL);129 130 if(m_hCom == INVALID_HANDLE_VALUE) {131
//dwError = GetLastError();132
// handle error 133
return FALSE;134 }135 else136 {137
SetCommMask( m_hCom, EV_RXCHAR ) ; // get any early notifications138
SetupComm( m_hCom, 4096, 4096 ) ; // setup device buffers139
// purge any information in the buffer140 141
PurgeComm( m_hCom, PURGE_TXABORT | PURGE_RXABORT |PURGE_TXCLEAR | PURGE_RXCLEAR ) ;142 143
// set up for overlapped I/O144 145
DWORD dwTemp = 1000 / (this->m_dwBaudRate / 8);146
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF ;147
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;//((dwTemp > 0) ? dwTemp : 1);148
CommTimeOuts.ReadTotalTimeoutConstant = 1000 ;149 150
// CBR_9600 is approximately 1byte/ms. For our purposes, allow151
// double the expected time per character for a fudge factor.152 153
CommTimeOuts.WriteTotalTimeoutMultiplier =2*CBR_9600/this->m_dwBaudRate;//( npTTYInfo ) ;154
CommTimeOuts.WriteTotalTimeoutConstant = 0;//1000 ;155 156
SetCommTimeouts( m_hCom, &CommTimeOuts ) ;157 }158 if(!SetupConnection())159 {160
CloseConnection();161
return FALSE;162 }163 EscapeCommFunction( m_hCom, SETDTR );164 m_bConnected = TRUE;165 return TRUE;166 }167 168 BOOL CComStatus::CloseConnection()169 {170 if (NULL == m_hCom)171
return ( TRUE ) ;172 // set connected flag to FALSE173 m_bConnected = FALSE;174 // disable event notification and wait for thread175 // to halt176 SetCommMask( m_hCom, 0 ) ;177 EscapeCommFunction( m_hCom, CLRDTR ) ;178 // purge any outstanding reads/writes and close device handle179 PurgeComm( m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ;180 CloseHandle( m_hCom ) ;181 m_hCom = NULL;182 183 // change the selectable items in the menu184 185 CloseHandle(m_rdos.hEvent);186 CloseHandle(m_wtos.hEvent);187 return ( TRUE ) ;188 }189 190 BOOL CComStatus::SetupConnection()191 {192 BOOL fRetVal ;193 BYTE bSet ;194 DCB dcb ;195 if(m_hCom == NULL)196
return FALSE; 197 dcb.DCBlength = sizeof( DCB ) ;198 GetCommState( m_hCom, &dcb ) ;199 dcb.BaudRate = this->m_dwBaudRate;200 dcb.ByteSize = this->m_bByteSize;201 dcb.Parity = this->m_bParity;202 dcb.StopBits = this->m_bStopBits ;203 dcb.EvtChar = this->m_bEvtChar ;204 // setup hardware flow control205 bSet = (BYTE) ((m_bFlowCtrl & FC_DTRDSR) != 0) ;206 dcb.fOutxDsrFlow = bSet ;207 if (bSet)208
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE ;209 else210
dcb.fDtrControl = DTR_CONTROL_ENABLE ;211 bSet = (BYTE) ((m_bFlowCtrl & FC_RTSCTS) != 0) ;212 dcb.fOutxCtsFlow = bSet ;213 if (bSet)214
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE ;215 else216
dcb.fRtsControl = RTS_CONTROL_ENABLE ;217 // setup software flow control218 bSet = (BYTE) ((m_bFlowCtrl & FC_XONXOFF) != 0) ;219 dcb.fInX = dcb.fOutX = bSet ;220 dcb.XonChar = ASCII_XON ;221 char xon = ASCII_XON ;222 dcb.XoffChar = ASCII_XOFF ;223 char xoff = ASCII_XOFF ;224 dcb.XonLim = 100 ;225 dcb.XoffLim = 100 ;226 // other various settings227 dcb.fBinary = TRUE ;228 dcb.fParity = TRUE ;229 fRetVal = SetCommState( m_hCom, &dcb ) ;230 return ( fRetVal ) ;231 } // end of SetupConnection()232 233 BOOL CComStatus::IsConnected()234 {235 return m_bConnected;236 }237 238 UINT CommWatchProc( LPVOID lpData )239 {240 DWORD dwEvtMask ;241 //NPTTYINFO npTTYInfo = (NPTTYINFO) lpData ;242 OVERLAPPED os ;243 int nLength ;244 //BYTE abIn[ MAXBLOCK + 1] ;245 246 CComStatus * pCom = (CComStatus *)lpData;247 memset( &os, 0, sizeof( OVERLAPPED ) ) ;248 // create I/O event used for overlapped read249 250 os.hEvent = CreateEvent( NULL, // no security251
TRUE, // explicit reset req252
FALSE, // initial event reset253
NULL ) ; // no name254 255 if (os.hEvent == NULL)256 {257
MessageBox( NULL, "Failed to create event for thread!", "TTY Error!",MB_ICONEXCLAMATION | MB_OK ) ;258
return ( FALSE ) ;259 }260 if (!SetCommMask( pCom->m_hCom, EV_RXCHAR ))261
return ( FALSE ) ;262 char buf[256];263 while ( pCom->m_bConnected )264 {265
dwEvtMask = 0 ;266
WaitCommEvent( pCom->m_hCom, &dwEvtMask, NULL );267
if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR)268
{269
if ((nLength = ReadCommBlock( *pCom, (LPSTR) buf, 255 )))270
{271
//WriteTTYBlock( hTTYWnd, (LPSTR) abIn, nLength ) ;272
buf[nLength]="\0";273
AfxMessageBox(buf);274
}275
}276 }277 CloseHandle( os.hEvent ) ;278 return( TRUE ) ;279 } // end of CommWatchProc()280 281 int ReadCommBlock(CComStatus& comDev,LPSTR lpszBlock, int nMaxLength )282 {283 BOOL fReadStat ;284 COMSTAT ComStat ;285 DWORD dwErrorFlags;286 DWORD dwLength;287 DWORD dwError;288 289 char szError[ 10 ] ;290 291 // only try to read number of bytes in queue292 293 ClearCommError( comDev.m_hCom, &dwErrorFlags, &ComStat ) ;294 dwLength = min( (DWORD) nMaxLength, ComStat.cbInQue ) ;295 296 if (dwLength > 0)297 {298
fReadStat = ReadFile( comDev.m_hCom, lpszBlock,dwLength, &dwLength, &(comDev.m_rdos) ) ;299
if (!fReadStat)300
{301
if (GetLastError() == ERROR_IO_PENDING)302
{303
OutputDebugString("\n\rIO Pending");304
while(!GetOverlappedResult( comDev.m_hCom ,&(comDev.m_rdos), &dwLength, TRUE ))305
{306
dwError = GetLastError();307
if(dwError == ERROR_IO_INCOMPLETE)308
// normal result if not finished309
continue;310
else311
{312
// an error occurred, try to recover313
wsprintf( szError, "", dwError ) ;314
ClearCommError( comDev.m_hCom , &dwErrorFlags, &ComStat ) ;315
break;316
}317
}318
}319
else320
{321
// some other error occurred322
dwLength = 0 ;323
ClearCommError( comDev.m_hCom , &dwErrorFlags, &ComStat ) ;324
}325
}326 }327 return ( dwLength ) ;328 } // end of ReadCommBlock()329 330 int ReadCommBlockEx(CComStatus& comDev,LPSTR lpszBlock, int nMaxLength,DWORD dwTimeOut)331 {332 LPSTR lpOffset=lpszBlock;333 int nReadCount = 0;334 char chBuf;335 //time_t beginTime,endTime;336 if(!comDev.m_hCom)337
return 0;338 if(dwTimeOut <= 0)339
return 0;340 MSG msg;341 //time(&beginTime);342 DWORD dwLastTick,dwNowTick,dwGoneTime;343 dwGoneTime = 0;344 dwLastTick = GetTickCount();345 dwNowTick = dwLastTick;346 // double diftime;347 do348 {349
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))350
{351
::TranslateMessage(&msg);352
::DispatchMessage(&msg);353
}354
if(ReadCommBlock(comDev,&chBuf,1) > 0)355
{356
//TRACE("----get a char----\n");357
*lpOffset = chBuf;358
lpOffset ++;359
nReadCount ++;360
}361
dwNowTick = GetTickCount();362
if(dwNowTick < dwLastTick)363
{364
dwLastTick = dwNowTick;365
}366 367
dwGoneTime = dwNowTick - dwLastTick;368 369
//TRACE("gon time = %lu\n",dwGoneTime);370 371 }while((nReadCount < nMaxLength) && (dwGoneTime < dwTimeOut));372 return (nReadCount);373 }//end ReadCommBlockEx374 375 BOOL WriteCommBlock( CComStatus& comDev, LPSTR lpByte , DWORD dwBytesToWrite)376 {377 BOOL fWriteStat ;378 DWORD dwBytesWritten ;379 DWORD dwErrorFlags;380 DWORD dwError;381 DWORD dwBytesSent=0;382 COMSTAT ComStat;383 384 char szError[ 128 ] ;385 386 fWriteStat = WriteFile( comDev.m_hCom , lpByte, dwBytesToWrite,&dwBytesWritten, &( comDev.m_wtos) ) ;387 if (!fWriteStat)388 {389
if(GetLastError() == ERROR_IO_PENDING)390
{391
while(!GetOverlappedResult( comDev.m_hCom,&(comDev.m_wtos), &dwBytesWritten, TRUE ))392
{393
dwError = GetLastError();394
if(dwError == ERROR_IO_INCOMPLETE)395
{396
// normal result if not finished397
dwBytesSent += dwBytesWritten;398
continue;399
}400
else401
{402
// an error occurred, try to recover403
wsprintf( szError, "", dwError ) ;404
ClearCommError( comDev.m_hCom, &dwErrorFlags, &ComStat ) ;405
break;406
}407
}408
dwBytesSent += dwBytesWritten;409
if( dwBytesSent != dwBytesToWrite )410
wsprintf(szError,"\nProbable Write Timeout: Total of %ld bytes sent", dwBytesSent);411
else412
wsprintf(szError,"\n%ld bytes written", dwBytesSent);413
OutputDebugString(szError);414
}415
else416
{417
// some other error occurred418
ClearCommError( comDev.m_hCom, &dwErrorFlags, &ComStat ) ;419
return ( FALSE );420
}421 }422 return ( TRUE ) ;423 } // end of WriteCommBlock()
四、小结 以上给出了用Win32 API设计串行通信的基本思路,在实际应用中,我们可以利用Win32 API设计出满足各种需要的串行通信程序。
欢迎各位电子爱好者转载。
PS原文出自http://soft.yesky.com/50/2214050_2.shtml
标签:
相关推荐:
最新新闻:
- 世界热文:c语言餐桌游戏有哪些?教会你这十款酒桌游戏让你在朋友圈稳站“C”位!
- 电脑默认网关如何查询?电脑默认网关查询的小技巧
- IE浏览器不见了怎么办?IE浏览器不见了解决方法
- Win7专业版与Win7旗舰版如何区分?Win7专业版与Win7旗舰版区分方法
- Win7系统安装声卡驱动失败怎么办?声卡驱动安装失败解决方法
- 百度快照如何彻底删除?百度快照正确的删除方法
- 英雄联盟无法全屏显示如何解决?英雄联盟无法全屏显示解决方法
- 如何解决IE浏览器网页图片显示红叉问题?IE浏览器网页图片显示红叉解决方法
- Win7系统安装CAD软件提示缺少dfst.dll怎么办?解决方法
- 内网端口映射怎么设置?内网端口映射定义及设置方法
- 美拍是什么?美拍怎么用?
- 怎么关闭微信的扫脸支付功能?微信的扫脸支付功能关闭步骤
- 基础版本的基础版本 直方图均衡化系列
- 天天要闻:图片或手写签名转电子签名怎么转?手写签名转电子签名教程
- 观点:颜料墨水和染料墨水的区别是什么?颜料墨水和染料墨水简介
- 每日看点!用VC6.0怎么实现上位机串口通信?位机串口通信的设置方法
- ssm大学生兼职论坛是什么?大学生兼职有哪些?:每日观察
- 许多推倒重建正在发生 | 独家对话索尼互娱中国总裁
- 会议panel是什么意思?医学术语中的panel到底是指什么?
- 浪漫主义时期的音乐有哪些?浪漫主义乐派是什么?-当前独家
- 今日视点:怎么设置交换机?计算机交换机连接设置方法
- Android中LayoutParams是什么?Android中LayoutParams总结和用法
- 摄氏度和开氏度的换算 开氏度和摄氏度的换算公式 天天亮点
- PSVR2首发获两款老游戏强化!可4K、90帧运行
- 天天速递!粘胶短纤维市场现状是什么?粘胶短纤维的未来发展趋势
- 今日热门!数据结构试题有哪些?数据结构试题及评分解析
- 传英伟达RTX 4070Ti首发价899美元 约合RMB 6268元|环球资讯
- 关注:《铁拳8》TGA预热视频 2023年发售
- 天天速看:CDP警告员工《巫师》AR手游停服后将会进行裁员
- 二代接班,一场父与子的「明争暗战」 全球新动态
- 世界观点:看不起英特尔独显?一个驱动更新游戏帧数提升80%
- 游戏玩家抓紧更新!Win 11修复重大性能BUG 帧率显著提升
- 【新要闻】育碧:《纪元1800》于今日返回Steam平台
- 朴叙俊将加盟《惊奇队长2》 演惊奇队长丈夫|当前头条
- 《高达 水星魔女》一阶段最终话暂停 明年1月8日续播
- 泛娱乐出海拉美,茄子科技(海外SHAREit Group)助力企业有效获客
- 《暗黑4》新预告片将在明早1点公开_每日聚焦
- 全球视讯!《微软飞行模拟》玩家达到了1000万
- 【环球时快讯】一起教育科技发布2022年三季度财报:连续四个季度实现盈利
- 国产处理器龙芯发威了 下一代单核性能提升68%
- 在云南沙溪,这群年轻人每天做的事是「什么也不做」 每日视讯
- 2部国产动画获奥斯卡参评资格:豆瓣分别7.0分、5.8分 今日关注
- 【全球聚看点】全球首款8000MHz频率内存开卖 32GB售价4888元
- 4999元 你能买到的最低价12代标压i5+RTX3050游戏本来了|当前报道
- 把iMac按在地上摩擦 4K屏+RTX 3060独显微软Surface一体电脑预售中|重点聚焦
- Windows 11免费升级新招 Windows 7也能用:全球今头条
- 普京表示核战争的风险正在上升,没有继续进行动员的必要
- 世界速看:玩家注意升级:Win11更新补丁修复游戏性能问题
- 焦点热议:想要畅玩《老头环》?高颜值游戏本双十二杀到7599元
- RTX 4080全球销售低迷 网友:太贵了 我再等等_世界速递
- 小牛电动车创始人造车失败 汽车圈真不是谁都能进!
- 世界通讯!传说中的苹果电车:不是全自动驾驶了!
- 竞猜赢大礼:2022世界杯竞猜 惊喜大礼等你拿
- 全球聚焦:《木卫四协议》发布PC性能补丁 减少卡顿
- PlayStation联机免费周末来了!《艾尔登法环》斗技场PVP玩家别急开会员
- 观速讯丨我们在监狱里做了一个行为经济学实验
- 《狂野之心》公开全新概念图 将出席TGA|环球最资讯
- 全球动态:《神秘海域》新作或在开发中 顽皮狗只做协助
- 《死亡空间》原版与重制版早期图像对比视频 全球热门
- 微软表示《微软飞行模拟》已突破1000万玩家-全球热点
- 全新VR农场模拟游戏《横跨山谷》公布
- 快看点丨华尔街裁员潮加速蔓延!摩根士丹利裁员1600人
- 入冬最销魂的一口,莫过于它
- 主动“走失”又归来的小镇少年们
- 2022日本东京大学校花冠军出炉 甜美可爱的学霸妹子-世界头条
- 《刺客信条:英灵殿》Steam遇冷 峰值只有3527人
- 【世界报资讯】网飞联席CEO:还没看到体育赛事直播的盈利模式
- 《毁灭全人类2》公布节日皮肤 免费更新_全球资讯
- 1TB固态SSD再降价 到手限时294元
- 天天快资讯:国产大厂们的开放世界野望,究竟能实现几成?
- “索尼克之父”中裕司又因内幕交易被捕 涉案金额超1亿日元
- 全球快消息!扬州琼都歌舞厅:欢迎来到80年代
- 《阿凡达2》中国内地预售首日总票房突破千万
- 拐点已至!碳酸锂价格连续10日下跌
- 环球资讯:演恶毒女配的北漂演员,已经抢先停止内耗了