I have the most current Renci.SshNet.dll loaded in my application's path, but I'm getting the message "Unable to load SFTP Client. Make sure Renci.SshNet.dll is available." when attempting to create the wwSFTP object.
Make sure wwDotnetBridge, wwIPstuff and the Renci DLL are a matched set. Latest update rev'd the version of the DLL so wwDotnetBridge which loads it has to match (or be at least of the same or later version for the Renci dll).
+++ Rick ---
I just installed 7.23 a few days ago. It looks like all of these are current - Renci.SshNet.dll is 10.16.2017 wwIPstuff is 08.14.2021 wwDotnetBridge is 08.14.2021
Sorry for the delay...
Argh... looks like I didn't update the DLL in the Client Tools package. Checked and sure enough I was able to duplicate the error you saw.
Updated the DLL and updated the download packages, so re-download.
Sorry about the hassle.
Aloha,
+++ Rick ---
Thank you so much for your quick reply. I went back to your email and downloaded the latest .zip. Is there a different password now? I see the dll that has been updated, but I'm unable to extract it.
I was able to find and download Renci.SshNet.dll from a different source. This does solve my problem when creating the wwSFTP object. I'm able to connect to my ftp server, but FTPGetFileEx fails in ONFTPBUFFERUPDATE which is called from this function. The error is "must identify additional parameters".
FTPGetFile works fine for me.
Hmmm... works for me. I'm just running the tests in .\tests\wwsftptests.prg
using the Rebex local SFTP server.
This works:
FUNCTION DownloadFile()
loFtp = CREATEOBJECT("wwSftp")
lcHost = "127.0.0.1"
lnPort = 23
lcUsername = "tester"
lcPassword = "password"
loFtp.cFtpServer = lcHost
loFtp.nFtpPort = lnPort
loFtp.cUsername = lcUsername
loFtp.cPassword = lcPassword
BINDEVENT(loFtp,"OnFtpBufferUpdate",this,"BufferUpdate")
lcOutputFile = ".\tests\sailbig_downloaded.jpg"
DELETE FILE lcOutputFile
loFtp.FtpConnect()
lnResult = loFtp.FtpGetFileEx("sailbig.jpg",lcOutputFile)
loFtp.FtpClose()
this.AssertTrue(lnResult == 0,loFtp.cErrorMsg)
this.AssertTrue(FILE(lcOutputFile))
ENDFUNC
FUNCTION BufferUpdate(lnbytesdownloaded,lnbufferreads,lccurrentchunk, lnTotalBytes, loFtp)
WAIT WINDOW NOWAIT TRANSFORM(lnBytesDownloaded) + " of " + TRANSFORM(lnTotalBytes)
ENDFUNC
DO wwftp
DO wwsftp
o=create("wwSFTP")
o.lPassiveFTP = .T.
o.nFtpPort = 9122
lnStat = o.FTPConnect(pcCPSite1,pcCPUser1,pcCPU2020)
IF lnStat = 0
lnStat = o.FTPGetFileEx("ver2020.txt",pcPath+"test.txt")
ENDIF
I guess it's the missing BINDEVENT? How would that be coded in this simple program?
The BindEvent()
isn't required that's just for the message event hooking. You can comment that out and it should still work.
+++ Rick ---
DO wwftp
DO wwsftp
o=create("wwSFTP")
o.lPassiveFTP = .T.
o.nFtpPort = 9122
SET STEP ON
lnStat = o.FTPConnect(pcCPSite1,pcCPUser1,pcCPU2020)
IF lnStat = 0
lcOutputFile = ".\tests\sailbig_downloaded.jpg"
lcOutputFile = "c:\temp\test.txt"
lnStat = o.FTPGetFileEx("ver2020.txt",lcOutputFile)
ENDIF
Interesting, it turns out to be lcOutputFile. Why does yours work and mine does not? On my computer c:\temp is a valid folder.
If I run with a bad output file name this is what it looks like:
Just to be sure re-download the full Client Tools and make sure you have the right versions of files. I fixed the password (not sure what was wrong with the last upload)...
+++ Rick ---
I'm happy to stick with this because it's working just fine. I'm having trouble comprehending how what's specified for the output file works for ftpgetfile but not for ftpgetfileex
DO wwftp
DO wwsftp
o=create("wwSFTP")
o.lPassiveFTP = .T.
o.nFtpPort = 9122
lnStat = o.FtpGetFile(pcCPSite1,"ver2020.txt","c:\temp\test.txt",1,pcCPUser1,pcCPU2020)
Try deleting the file beforehand? That could be the difference. The simple API does a bunch of work that the lower level routine does not.
+++ Rick ---
A delete file didn't change anything. I'll stick with the simple API. ftpgetfileex has always worked fine for me with FTP. It must be something with my implementation of WW - I have the same problems when trying an older release of your utilities.
Can I ask one last favor on this one? Can you please try a test of this code and confirm that a lcOutputFile with a value of a file qualified with an exact path and file like I'm doing does in fact work for you? In other words, after the process runs, you have a file that was transferred from the server. Using a directory you know exists, something like "c:\temp\sailbig_downloaded.jpg". My finding is the only time I don't get the error is when the get fails - invalid path, for example. When I have a valid path and file name, the data transfer actually succeeds - it must be the last call to the buffering routine that's failing with an incorrect number of parameters. So, my solution right now is just to ignore this error.
I'm converting my application from FTP to SFTP and I take advantage of the method onftpbufferupdate that you suggest in the documentation. It really works well for showing download progress. Would this also be something I could do in SFTP?
Not sure what you're asking. The code takes the input file name and runs FULLPATH()
on it so it shouldn't matter whether you specify a relative or full path. If the path is invalid you get a different error as soon as the first buffer is written to disk:
Could not find a part of the path 'C:\WEBCONNECTION\FOX\TESSTS\SAILBIG_DOWNLOADED.JPG'.
lcOutputFile = ".\tessts\sailbig_downloaded.jpg"
DELETE FILE lcOutputFile
loFtp.FtpConnect()
*** result is 0
lnResult = loFtp.FtpGetFileEx("sailbig.jpg",lcOutputFile)
loFtp.FtpClose()
*** Error is captured in cErrorMsg
this.AssertTrue(lnResult == 0,loFtp.cErrorMsg)
this.AssertTrue(FILE(lcOutputFile))
+++ Rick ---
I'm converting my application from FTP to SFTP and I take advantage of the method onftpbufferupdate that you suggest in the documentation. It really works well for showing download progress. Would this also be something I could do in SFTP?
Yes works the same although I think the parameters passed to the even method is different.
The BINDEVENT()
code in the original code sample (or in the Tests) demonstrates how you can do this, but it's the same as in wwFtp
.
I am so sorry for this wild goose chase. I finally did an entire project search for the function that was failing. I found that I was still loading an ancient ipstuff class. Once I removed that, everything's just fine.
Thank you for your excellent support!!