Modifying Wininet,dll to implement Pause & Resume at FTP Protocol leve






2.47/5 (7 votes)
Aug 16, 2005
4 min read

52300
Wininet API can not support the function of resume but we can modify wininet.dll to support it.
Introduction
I have read the article “Pause & Resume at Protocol level. (You can implement it in any language)” By Narendra Chandel . But his work does not work on many server. I sniffed the TCP packages and found the commands ,which Wininet API sent, does not match W
Programmatically starting download pausing and then restarting again
Let say for example you are downloading a file: MyHugeFooFile.zip.
- Typically send a RETRIEVE (RETR) command for file MyHugeFooFile.zip to the FTP server to start download. Store data received from server to a temp file for example Temp_MyHugeFooFile.zip. So any time download is aborted, size of temp file is the actual useful data transferred so far of MyHugeFooFile.zip.
- Let say all of a sudden ISP connection is broken or FTP server is down or your FTP client crashed or you manually stopped the download.
- Now Next time when you want to restart download, read the size of temp file (i.e. useful data downloaded so far), and seek to the end of the temp file so further download will append the data from end.
- Now send a REST command to FTP server and pass the file size of temp file as parameter. (a typical syntax would be REST 250 if size of temp file was 250). FTP server will send a response stating something like "Restarting from byte 250..".
- Now you can send RETRIEVE (RETR) again for file MyHugeFooFile.zip and FTP server will start sending data from byte offset 251 onwards.
- Now it is your responsibility to append the data coming from server to the incomplete file Temp_MyHugeFooFile.zip and you are all set.
- Once the transfer is complete rename the temp file to the actual file name on WINDOWS using C++ it should typically look like
RenameFile(Temp_MyHugeFooFile.zip, MyHugeFooFile.zip);
Done.
Programmatically determining if a particular FTP server supports Pause & Resume
Three simple steps
- Once connected to FTP server try sending a REST command with 0 ( zero ) as argument.
- If commands fail or server return something like command is not supported. That means this server doesn't support Pause and Resume.
- If FTP server return a response stating something like "Restarting from byte 0" that means server supports Pause & Resume
Now if you just started writing code you may have question, how to send these commands the FTP server. Answer is so many ways. Raw socket is one, WinInet is another. In my sample code I have utilized WinInet's API FtpCommand to send direct commands to FTP server.
How Wininet API work
BOOL WINAPI FtpOpenFile(
HINTERNET hConnect,
LPCTSTR lpszFileName,
DWORD dwAccess,
DWORD dwFlags,
DWORD dwContext);
Three simple steps
1,Type to I PASV
2,SIZE filename
3, some nouse action
If we change SIZE filename command to REST pos ,it would resume from pos.
so I modify the function like this:
BOOL WINAPI FtpOpenFile(
HINTERNET hConnect,
LPCTSTR lpszFileName,
DWORD dwAccess,
DWORD dwFlags,
LPCTSTR *plpszSeekPos );
the argument plpszSeekPos is used as follow:
CString sSeekPos;
SSeekPos.Format("%ld",dwSeekPos);
lpSeekPose=sSeekPos.LockBuffer();
plpszSeekPos=&lpSeekPose;
Modify Wininet.dll
Debug into FTPOpenFile function ,F11 F11 ....
then you would find three function entry to format string:
761BB256 and ebx,80000000h
761BB25C mov eax,761DE8F0h
………………………………………………………
761BB261 jne 761BB268
761BB263 mov eax,761DE8E8h
761BB276 call 761BC0A2
format("RETR %s");
761BC213 push edi
761BC214 mov edi,dword ptr [ebp+70h]
761BC217 push eax
761BC218 push 761DE9ECh
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
761BC21D push edi
761BC21E push 0
761BC225 call 761BC1C3
format("TYPE %s");
761BC7F9 test eax,eax //没有用
761BC7FB jne 761BC89D //没有用
761BC801 push dword ptr [ebp+78h]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lpstrFileAtServer
761BC804 push 761DE93Ch
761BC809 push dword ptr [ebp+58h]
761BC80C call 761BC003
format("SIZE %s",lpstrFileAtServer)
Replace string resource first. change SIZE %s to REST %s.
At address 761BC7F9:
761BC7F9 85 C0 0F 85 9C 00 00 吚.厹..
761BC800 00 FF 75 78
761BC7F9 test eax,eax
761BC7FB jne 761BC89D
761BC801 push dword ptr [ebp+78h]
Modify the 11 bytes to:
761BC7F9 90 8B C5 05 50 01 00 悑..P..
761BC800 00 50 90 90
nop;
mov eax, ebp ;
add eax, 0x150 ;
push eax ;
nop;
nop;
that's DONE!.
Usage
char lpPos[64];//note: lpPos must in stack not in heap
memset(lpPos,0,64);
sprintf(lpPos,"%ld",dOffsetToSeek);
m_hOpenFile = ::FtpOpenFile(m_hOpenUrlHandle,sFileNameAtServer
, GENERIC_R
EAD
, FTP_TRANSFER_TYPE_BINARY, (DWORD)&lpPos);
Note
You should put this modified dll in current directory.