UltraVNC:C++源码分析远程文件传输界面显示远程端文件系统流程

UltraVNC:C++源码分析远程文件传输界面显示远程端文件系统流程

UltraVNC远程文件传输客户端主要在 FileTransfer.cpp 处理,服务端主要在 vncclient.cpp 处理。

另外这里顺便提一下windows下文件属性结构体 : WIN32_FIND_DATA
前面44个字节表示文件属性。
FILETIME结构持有的64位无符号的文件的日期和时间值。此值表示自1601年1月1日开始的100纳秒为单位的时间。

typedef struct _WIN32_FIND_DATA {
    
    
    DWORD dwFileAttributes; //文件类型,4个字节
    FILETIME ftCreationTime; // 文件创建时间,8个字节
    FILETIME ftLastAccessTime; // 文件最后一次访问时间,8个字节
    FILETIME ftLastWriteTime; // 文件最后一次修改时间,8个字节
    DWORD nFileSizeHigh; // 文件长度高32位,指向内存地址的指针,一般是0,4个字节
    DWORD nFileSizeLow; // 文件长度低32位,内存大小,4个字节
    DWORD dwReserved0; // 系统保留,4个字节
    DWORD dwReserved1; // 系统保留,4个字节
    TCHAR cFileName[ MAX_PATH ]; // 长文件名
    TCHAR cAlternateFileName[ 14 ]; // 8.3格式文件名
} WIN32_FIND_DATA, *PWIN32_FIND_DATA;

第一部分 客户端文件传输界面显示远程端磁盘信息

客户端请求远程端磁盘信息

//
// request the list of remote drives 
//
void FileTransfer::RequestRemoteDrives()
{
    
    
//	vnclog.Print(0, _T("RequestRemoteDrives\n"));
	if (!m_fFTAllowed) return;

	// TODO : hook error !
    rfbFileTransferMsg ft;
    ft.type = rfbFileTransfer;
	ft.contentType = rfbDirContentRequest;
    ft.contentParam = rfbRDrivesList; // List of Remote Drives please
	ft.length = 0;
    m_pCC->WriteExact((char *)&ft, sz_rfbFileTransferMsg, rfbFileTransfer);

	return;
}

服务端接收请求,然后获取系统磁盘信息
获取磁盘信息的接口是 dwLen = GetLogicalDriveStrings(256, szDrivesList);

// The client requests the content of a directory or Drives List
case rfbDirContentRequest:
	switch (msg.ft.contentParam)
	{
    
    
		// Client requests the List of Local Drives
		case rfbRDrivesList:
			{
    
    
               ...
			}
			break;

		// Client requests the content of a directory
		case rfbRDirContent:
			{
    
    
               ...
			}
			break;
	}
	break;

服务端发送系统磁盘信息给客户端

rfbFileTransferMsg ft;
ft.type = rfbFileTransfer;
ft.contentType = rfbDirPacket;
ft.contentParam = rfbADrivesList;
ft.length = Swap32IfLE((int)dwLen);
//adzm 2010-09 - minimize packets. SendExact flushes the queue.
m_socket->SendExactQueue((char *)&ft, sz_rfbFileTransferMsg, rfbFileTransfer);
m_socket->SendExact((char *)szDrivesList, (int)dwLen);

客户端接收磁盘信息,并处理 ListRemoteDrives(hWnd, Swap32IfLE(ft.length));

case rfbADrivesList:
	ListRemoteDrives(hWnd, Swap32IfLE(ft.length));
	m_fFileCommandPending = false;
	break;

第二部分 客户端文件传输界面显示远程端某个磁盘内具体信息

客户端请求远程端发送某个磁盘下具体文件夹信息

//
// Request the contents of a remote directory
//
void FileTransfer::RequestRemoteDirectoryContent(HWND hWnd, LPSTR szPath)
{
    
    
//	vnclog.Print(0, _T("RequestRemoteDirectoryContent\n"));
	if (!m_fFTAllowed)
	{
    
    
		m_fFileCommandPending = false;
		return;
	}

	char ofDir[MAX_PATH];
	char ofDirT[MAX_PATH];
	int nSelected = -1;
	int nCount = 0;
	HWND hWndRemoteList = GetDlgItem(hWnd, IDC_REMOTE_FILELIST);

	ofDir[0] = '\0';
	ofDirT[0] = '\0';

	if (lstrlen(szPath) == 0)
	{
    
    
		nCount = ListView_GetItemCount(hWndRemoteList);
		for (nSelected = 0; nSelected < nCount; nSelected++)
		{
    
    
			if(ListView_GetItemState(hWndRemoteList, nSelected, LVIS_SELECTED) & LVIS_SELECTED)
			{
    
    
				LVITEM Item;
				Item.mask = LVIF_TEXT;
				Item.iItem = nSelected;
				Item.iSubItem = 0;
				Item.pszText = ofDirT;
				Item.cchTextMax = MAX_PATH;
				ListView_GetItem(hWndRemoteList, &Item);
				break;
			}
		}
	}
	else
	{
    
    
		if (!IsShortcutFolder(szPath))
			szPath[6] = '\0';
		// szPath always contains a drive letter (X:) or (..)
		strcpy(ofDirT, szPath);
		// In the case of (..) we keep the current path intact
		char szUpDirMask[16];
		sprintf(szUpDirMask, "%s..%s", rfbDirPrefix, rfbDirSuffix);
		if (strcmp(ofDirT, szUpDirMask))
			SetDlgItemText(hWnd, IDC_CURR_REMOTE, "");
	}

	if (nSelected == nCount || lstrlen(ofDirT) == 0)
	{
    
    
		GetDlgItemText(hWnd, IDC_CURR_REMOTE, ofDirT, sizeof(ofDirT));
		if (strlen(ofDirT) == 0) 
		{
    
    
			m_fFileCommandPending = false;
			return; 
		}
	}
	else
	{
    
    
		if (ofDirT[0] == rfbDirPrefix[0] && ofDirT[1] == rfbDirPrefix[1])
		{
    
    
			strncpy(ofDir, ofDirT + 2, strlen(ofDirT) - 3); 
			ofDir[strlen(ofDirT) - 4] = '\0';
		}
		else
		{
    
    
			m_fFileCommandPending = false;
			return;
		}

		GetDlgItemText(hWnd, IDC_CURR_REMOTE, ofDirT, sizeof(ofDirT));
		if (!_stricmp(ofDir, ".."))
		{
    
    	
			char* p;
			ofDirT[strlen(ofDirT) - 1] = '\0';
			p = strrchr(ofDirT, '\\');
			if (p == NULL)
			{
    
    
				m_fFileCommandPending = false;
				return;
			}
			*p = '\0';
		}
		else
			strcat(ofDirT, ofDir);
		strcat(ofDirT, "\\");
		SetDlgItemText(hWnd, IDC_CURR_REMOTE, ofDirT);
	}
	strcpy(ofDir, ofDirT);

	// Todo: In case of shortcuts dir, do a translation here !

	// Select the good drive in the drives combo box (the first time only)
	int nIndex = SendDlgItemMessage(hWnd, IDC_REMOTE_DRIVECB, CB_GETCURSEL, 0, 0L);
	if (nIndex == LB_ERR)
	{
    
    
	    char szDrive[5];
		strcpy(szDrive, rfbDirPrefix);
	    strncat(szDrive, ofDir, 2);
	    nIndex = SendDlgItemMessage(hWnd, IDC_REMOTE_DRIVECB, CB_FINDSTRING, -1, (LPARAM)(LPSTR)szDrive); 
	    SendDlgItemMessage(hWnd, IDC_REMOTE_DRIVECB, CB_SETCURSEL, nIndex, 0L);
	}

	ListView_DeleteAllItems(hWndRemoteList);

    rfbFileTransferMsg ft;
    ft.type = rfbFileTransfer;
	ft.contentType = rfbDirContentRequest;
    ft.contentParam = rfbRDirContent; // Directory content please
	ft.length = Swap32IfLE(strlen(ofDir));
	//adzm 2010-09
    m_pCC->WriteExactQueue((char *)&ft, sz_rfbFileTransferMsg, rfbFileTransfer);
	m_pCC->WriteExact((char *)ofDir, strlen(ofDir));

	return;
}

服务端接收请求,然后获取文件夹信息

// The client requests the content of a directory or Drives List
case rfbDirContentRequest:
	switch (msg.ft.contentParam)
	{
    
    
		// Client requests the List of Local Drives
		case rfbRDrivesList:
			{
    
    
               ...
			}
			break;

		// Client requests the content of a directory
		case rfbRDirContent:
			{
    
    
               ...
			}
			break;
	}
	break;

获取文件夹内容主要方法

WIN32_FIND_DATA fd;
HANDLE ff;
BOOL fRet = TRUE;

ff = FindFirstFile(szDir, &fd);
while ( fRet )
{
    
    
    ...
    /*这里依次把文件夹下每个文件或者目录信息发送到客户端*/
    ....
	fRet = FindNextFile(ff, &fd);
}
FindClose(ff);

最后服务端发送结束标志

// End of the transfer
ft.contentParam = 0;
ft.length = Swap32IfLE(0);
m_socket->SendExact((char *)&ft, sz_rfbFileTransferMsg, rfbFileTransfer);

客户端接收服务端文件夹信息,这里有两个函数
PopulateRemoteListBox(hWnd, Swap32IfLE(ft.length)); 更新文件传输界面远程端显示的当前目录
ReceiveDirectoryItem(hWnd, Swap32IfLE(ft.length));更新文件传输界面远程端显示具体目录信息

case rfbDirPacket:
	switch (ft.contentParam)
	{
    
    
	// Response to a rfbRDrivesList request
	case rfbADrivesList:
		ListRemoteDrives(hWnd, Swap32IfLE(ft.length));
		m_fFileCommandPending = false;
		break;

	// Response to a rfbRDirContent request 
	case rfbADirectory:
	case rfbAFile:
		if (!m_fDirectoryReceptionRunning)
			PopulateRemoteListBox(hWnd, Swap32IfLE(ft.length));
		else
			ReceiveDirectoryItem(hWnd, Swap32IfLE(ft.length));
		break;
	default: // This is bad. Add rfbADirectoryEnd instead...
		if (m_fDirectoryReceptionRunning)
		{
    
    
			FinishDirectoryReception();
			m_fFileCommandPending = false;
		}
		break;

	}
	break;

猜你喜欢

转载自blog.csdn.net/qq_33594636/article/details/131973573
今日推荐