SFTP

220 views
Skip to first unread message

Rüdiger Fresemann

unread,
Jul 17, 2020, 7:53:20 AM7/17/20
to
Hi everybody,

Does anybody know a solution to use SFTP in VO Apps?

Til now I still use FTP, because it is included and it works, but in the
next time more and more server only use SFTP.

Does anybody have an idea or a different solution to download a big file
(some megabytes) in an VO-App?

THx for codes or Ideas.

Ruediger

Stavros Spanos

unread,
Jul 20, 2020, 7:57:35 AM7/20/20
to
Ruediger hello!

We use FTP2 ocx from Chillcat.

http://www.chilkatsoft.com/default.asp

Rüdiger Fresemann

unread,
Jan 14, 2022, 12:20:36 PMJan 14
to
Hi Stavros,

Can you tell me, which chilkat-modul do you use? Do you have a little
example for me? Some code, for example?

Thanks

Ruediger

Rüdiger Fresemann

unread,
Jan 14, 2022, 12:25:35 PMJan 14
to
Am 20.07.2020 um 13:57 schrieb Stavros Spanos:
... By the way... I think it is not usable for commercial, is it?
I need a solution for my customers, not for me alone...

Ruediger

Gerhard Bunzel

unread,
Jan 15, 2022, 3:13:16 AMJan 15
to
Hi Rüdiger,

no problem to use Chillcat for a commercial app:

From https://www.chilkatsoft.com/licensingExplained.asp
- The license is royalty-free, meaning that Chilkat redistributables (DLLs and shared libraries) may be included with your application's deployment/installer packages.
- Regardless of the type of license purchased, a Chilkat component can be used in any number of applications, and can be redistributed royalty-free with your applications to end-users.
- Licensing levels are: 1-Developer, Small Group (up to 4-Developers), and Team (up to 8 developers).


I use this dll: https://www.weonlydo.com/SFTPdll/sftp-library-dll.asp
- No need for installation. Copy only the dll file into the application path
- Only 209,- US$ for a developer license.
- Use it in asynchronous mode with events
- 100% royalty free components

Works great!

Best regards

Gerhard Bunzel

Rüdiger Fresemann

unread,
Jan 17, 2022, 5:04:28 AMJan 17
to
Hallo Gerhard,

Hast du vielleicht noch einen Schnipsel für mich?

Gerhard Bunzel

unread,
Jan 21, 2022, 7:22:06 AMJan 21
to
Hallo Rüdiger,

nachfolgend etwas Code. Der ist nicht schön - zum Testen sollte das aber funktionieren.
Wichtig ist bei den Events anscheinend der Aufruf von DoEvents() um die Nachrichten zu verarbeiten.
Ich hatte das einfach in einer Schleife getestet. In einer richtigen Sftp-Klasse mit den Funktionen würde das natürlich anders aussehen.
Die Funktionsaufrufe ohne die Verarbeitung der Events - einfach die Befehle nacheinander abarbeiten lassen - ist recht einfach und funktioniert gut.

HTH

Gerhard Bunzel


Die DEFINES:
DEFINE wodSFTP_typeDirectory := 0
DEFINE wodSFTP_typeSymlink := 1
DEFINE wodSFTP_typeFile := 2
DEFINE wodSFTP_typeTemporary := 3
DEFINE wodSFTP_typeUnknown := 4
// DirItemTypes

DEFINE wodSFTP_ZoneLocal := 0
DEFINE wodSFTP_ZoneUTC := 1
// TimezonesEnum

DEFINE wodSFTP_Binary := 0
DEFINE wodSFTP_AscII := 1
// TransferModesEnum

DEFINE wodSFTP_PermRead := 1
DEFINE wodSFTP_PermWrite := 2
DEFINE wodSFTP_PermCreate := 4
DEFINE wodSFTP_PermTruncate := 8
// RemotePermissions

DEFINE wodSFTP_Disconnected := 0
DEFINE wodSFTP_Connecting := 1
DEFINE wodSFTP_LogonInProgress := 2
DEFINE wodSFTP_Connected := 3
DEFINE wodSFTP_Receiving := 4
DEFINE wodSFTP_Sending := 5
DEFINE wodSFTP_Executing := 6
DEFINE wodSFTP_AccessingRawFile := 7
// StatesEnum

DEFINE wodSFTP_encAny := 0
DEFINE wodSFTP_encDES := 1
DEFINE wodSFTP_enc3DES := 2
DEFINE wodSFTP_encAES := 3
DEFINE wodSFTP_encBLOWFISH := 4
DEFINE wodSFTP_encAES128 := 5
DEFINE wodSFTP_encAES192 := 6
DEFINE wodSFTP_encAES256 := 7
DEFINE wodSFTP_encCAST128 := 8
DEFINE wodSFTP_encAEScbc := 9
DEFINE wodSFTP_encAESctr := 10
// EncryptionsEnum

DEFINE wodSFTP_authBoth := 0
DEFINE wodSFTP_authPassword := 1
DEFINE wodSFTP_authPubkey := 2
DEFINE wodSFTP_authSecurID := 3
DEFINE wodSFTP_authKeyboardInteractive := 4
DEFINE wodSFTP_authGSSAPI := 5
// AuthenticationsEnum

DEFINE wodSFTP_ProxyNone := 0
DEFINE wodSFTP_ProxySocks4 := 1
DEFINE wodSFTP_ProxySocks5 := 2
DEFINE wodSFTP_ProxyWEBStandard := 3
DEFINE wodSFTP_ProxyRelay := 4
DEFINE wodSFTP_ProxySocks4a := 5
DEFINE wodSFTP_ProxyWEBNtlmAuth := 6
DEFINE wodSFTP_ProxyWEBIntegratedAuth := 8
// ProxyTypes

Die DLL-Functions - nicht vollständig und auch nicht jede Funktion komplett getestet. Die fehlenden Funktionen können damit aber bestimmt selbst erstellt werden.
_DLL FUNCTION Sftp_Create (ptrSftpEventsStruct AS PTR, pszLicenseKey AS PSZ) AS PTR PASCAL:SftpDLL.Sftp_Create
_DLL FUNCTION Sftp_Destroy (ptrSftpDLL AS PTR) AS VOID PASCAL:SftpDLL.Sftp_Destroy
_DLL FUNCTION Sftp_Disconnect (ptrSftpDLL AS PTR) AS LONG PASCAL:SftpDLL.Sftp_Disconnect
_DLL FUNCTION Sftp_GetMyHostname (ptrSftpDLL AS PTR, pszBuffer AS PSZ, nSize REF LONG) AS LONG PASCAL:SftpDLL.Sftp_GetMyHostname
_DLL FUNCTION Sftp_GetMyIP (ptrSftpDLL AS PTR, pszBuffer AS PSZ, nSize REF LONG) AS LONG PASCAL:SftpDLL.Sftp_GetMyIP
_DLL FUNCTION Sftp_GetVersion (ptrSftpDLL AS PTR, pszBuffer AS PSZ, nSize REF LONG) AS LONG PASCAL:SftpDLL.Sftp_GetVersion
_DLL FUNCTION Sftp_GetBlocking (ptrSftpDLL AS PTR, lValue REF LOGIC) AS LONG PASCAL:SftpDLL.Sftp_GetBlocking
_DLL FUNCTION Sftp_SetBlocking (ptrSftpDLL AS PTR, lValue AS LOGIC) AS LONG PASCAL:SftpDLL.Sftp_SetBlocking
_DLL FUNCTION Sftp_SetHostname (ptrSftpDLL AS PTR, pszBuffer AS PSZ) AS LONG PASCAL:SftpDLL.Sftp_SetHostname
_DLL FUNCTION Sftp_GetPort (ptrSftpDLL AS PTR, nPort REF DWORD) AS LONG PASCAL:SftpDLL.Sftp_GetPort
_DLL FUNCTION Sftp_SetPort (ptrSftpDLL AS PTR, nPort AS DWORD) AS LONG PASCAL:SftpDLL.Sftp_SetPort
_DLL FUNCTION Sftp_SetLogin (ptrSftpDLL AS PTR, pszBuffer AS PSZ) AS LONG PASCAL:SftpDLL.Sftp_SetLogin
_DLL FUNCTION Sftp_Connect (ptrSftpDLL AS PTR) AS LONG PASCAL:SftpDLL.Sftp_Connect
_DLL FUNCTION Sftp_SetPassword (ptrSftpDLL AS PTR, pszBuffer AS PSZ) AS LONG PASCAL:SftpDLL.Sftp_SetPassword
_DLL FUNCTION Sftp_ListAttributes ( ptrSftpDLL AS PTR, pszRemotePath AS PSZ) AS LONG PASCAL:SftpDLL.Sftp_ListAttributes
_DLL FUNCTION Sftp_GetListItem (ptrSftpDLL AS PTR, pszBuffer AS PSZ, nSize REF LONG) AS LONG PASCAL:SftpDLL.Sftp_GetListItem
_DLL FUNCTION Sftp_PutFile (ptrSftpDLL AS PTR, pszLocalFile AS PSZ, pszRemotePath AS PSZ) AS LONG PASCAL:SftpDLL.Sftp_PutFile
_DLL FUNCTION Sftp_GetFile (ptrSftpDLL AS PTR, pszLocalFile AS PSZ, pszRemoteFile AS PSZ) AS LONG PASCAL:SftpDLL.Sftp_GetFile
_DLL FUNCTION Sftp_GetRemotePath (ptrSftpDLL AS PTR, pszBuffer AS PSZ, nSize REF LONG) AS LONG PASCAL:SftpDLL.Sftp_GetRemotePath
_DLL FUNCTION Sftp_SetRemotePath (ptrSftpDLL AS PTR, pszNewPath AS PSZ) AS LONG PASCAL:SftpDLL.Sftp_SetRemotePath
_DLL FUNCTION Sftp_GetLocalPath (ptrSftpDLL AS PTR, pszBuffer AS PSZ, nSize REF LONG) AS LONG PASCAL:SftpDLL.Sftp_GetLocalPath
_DLL FUNCTION Sftp_SetLocalPath (ptrSftpDLL AS PTR, pszNewPath AS PSZ) AS LONG PASCAL:SftpDLL.Sftp_SetLocalPath
_DLL FUNCTION Sftp_GetClientName (ptrSftpDLL AS PTR, pszBuffer AS PSZ, nSize REF LONG) AS LONG PASCAL:SftpDLL.Sftp_GetClientName
_DLL FUNCTION Sftp_SetClientName (ptrSftpDLL AS PTR, pszNewClient AS PSZ) AS LONG PASCAL:SftpDLL.Sftp_SetClientName
_DLL FUNCTION Sftp_MakeDir (ptrSftpDLL AS PTR, pszRemotePath AS PSZ) AS LONG PASCAL:SftpDLL.Sftp_MakeDir
_DLL FUNCTION Sftp_DeleteFile (ptrSftpDLL AS PTR, pszRemoteFile AS PSZ) AS LONG PASCAL:SftpDLL.Sftp_DeleteFile
_DLL FUNCTION Sftp_Abort (ptrSftpDLL AS PTR) AS LONG PASCAL:SftpDLL.Sftp_Abort
_DLL FUNCTION Sftp_GetState (ptrSftpDLL AS PTR, nState REF DWORD) AS LONG PASCAL:SftpDLL.Sftp_GetState
_DLL FUNCTION Sftp_GetStateText (ptrSftpDLL AS PTR, nState AS DWORD, pszBuffer AS PSZ, nSize REF LONG) AS LONG PASCAL:SftpDLL.Sftp_GetStateText
_DLL FUNCTION Sftp_GetErrorText (ptrSftpDLL AS PTR, nErrorCode AS SHORT, pszBuffer AS PSZ, nSize REF LONG) AS LONG PASCAL:SftpDLL.Sftp_GetErrorText
_DLL FUNCTION Sftp_GetLastError (ptrSftpDLL AS PTR, nErrorCode REF SHORT) AS LONG PASCAL:SftpDLL.Sftp_GetLastError
_DLL FUNCTION Sftp_SetTransferMode((ptrSftpDLL AS PTR, nValue AS SHORT) AS LONG PASCAL:SftpDLL.Sftp_SetTransferMode
_DLL FUNCTION Sftp_ListNames ( ptrSftpDLL AS PTR, pszRemotePath AS PSZ) AS LONG PASCAL:SftpDLL.Sftp_ListNames

Die Structure für die Events:
STRUCT SftpEventsStruct
MEMBER hConnected AS PTR
MEMBER hDisconnected AS PTR
MEMBER hStateChange AS PTR
MEMBER hHostFingerprint AS PTR
MEMBER hProgress AS PTR
MEMBER hListItems AS PTR
MEMBER hDone AS PTR
MEMBER hAttributes AS PTR
MEMBER hCryptoInformation AS PTR
MEMBER hAttributesData AS PTR
MEMBER hLoginChallenge AS PTR
MEMBER hLoopItem AS PTR
MEMBER hLoopError AS PTR
MEMBER hRemoteData AS PTR
MEMBER hExtendedCmdReply AS PTR

Die Prozeduren für den Empfang der Events:
PROCEDURE Sftp_Done (hWnd AS PTR, nErrorCode AS SHORT, pErrorText AS PSZ)

// _dOut(#Sftp_Done, hWnd, nErrorCode, pErrorText)

RETURN

PROCEDURE Sftp_Disconnected (hWnd AS PTR)

// _dOut(#Sftp_Disconnected, hWnd)

RETURN

PROCEDURE Sftp_Connected (hWnd AS PTR, nErrorCode AS SHORT, pErrorText AS PSZ)

// _dOut(#Sftp_Connected, hWnd, nErrorCode, Psz2String(pErrorText))

RETURN

PROCEDURE Sftp_StateChange (hWnd AS PTR, nOldState AS LONG)

// _dOut(#Sftp_StateChange, hWnd, nOldState)

RETURN

PROCEDURE Sftp_Progress (hWnd AS PTR, param1, param2)
// (hWnd AS PTR, nPosition AS I64Rec, nTotal AS I64Rec) AS VOID CALLBACK
// Mit den 64Bit-Parametern noch nicht getestet!!!!

// _dOut(#Sftp_Progress, hWnd, param1, param2)

RETURN


Etwas Code aus meinen Tests. Die Umschaltung zwischen 'normalem Funktionsaufruf' und 'ASync-Modus mit Events' erfolgt mit dem 'Sftp_SetBlocking()' und dem Sftp_Create() mit oder ohne erstem Parameter.

TEXTBLOCK Sample
LOCAL pSftpDLL AS PTR
LOCAL pBuf1, pBuf2 AS PSZ
LOCAL i, nCount AS INT
LOCAL nState AS DWORD
LOCAL nRet AS LONG
LOCAL cRet AS STRING
LOCAL nError AS SHORT
// LOCAL lRet AS LOGIC
LOCAL pEvent IS SftpEventsStruct

// LOCAL struFindData IS _winWIN32_FIND_DATA

nCount := 0

pEvent.hConnected := @Sftp_Connected ()
pEvent.hDisconnected := @Sftp_Disconnected ()
pEvent.hDone := @Sftp_Done ()
pEvent.hStateChange := @Sftp_StateChange ()
pEvent.hProgress := @Sftp_Progress ()

// pSftpDLL := Sftp_Create(NULL_PTR, String2Psz("LizenzKey"))
pSftpDLL := Sftp_Create(@pEvent, String2Psz("LizenzKey"))
pBuf1 := MemAlloc(10240)
pBuf2 := MemAlloc(1024)
MemSet(pBuf1, 0, 10240)
MemSet(pBuf2, 0, 1024)
i := 1024
nRet := Sftp_GetMyIP(pSftpDLL, pBuf2, @i)
cRet := Psz2String(pBuf2)
nRet := Sftp_GetMyHostname(pSftpDLL, pBuf2, @i)
cRet := Psz2String(pBuf2)

// Test zum Setzen und Lesen von Sftp_SetBlocking()
// nRet := Sftp_SetBlocking(pSftpDLL, TRUE)
// nRet := Sftp_GetBlocking(pSftpDLL, @lRet)
nRet := Sftp_SetBlocking(pSftpDLL, FALSE)
// nRet := Sftp_GetBlocking(pSftpDLL, @lRet)
// nRet := Sftp_SetBlocking(pSftpDLL, TRUE)

nRet := Sftp_SetHostname(pSftpDLL, String2Psz("www.MyServer.com"))
nRet := Sftp_SetLogin(pSftpDLL, String2Psz("MyTest"))

i := 1024
nRet := Sftp_GetVersion(pSftpDLL, pBuf2, @i)
cRet := Psz2String(pBuf2)
nRet := Sftp_SetPassword(pSftpDLL, String2Psz("MyPassword"))

nRet := Sftp_SetPort(pSftpDLL, 202)

// Status abfragen
nRet := Sftp_GetState(pSftpDLL, @nState)
i := 1024
nRet := Sftp_GetStateText(pSftpDLL, nState, pBuf2, @i)
cRet := Psz2String(pBuf2)

nRet := Sftp_GetLastError(pSftpDLL, @nError)
i := 1024
nRet := Sftp_GetErrorText(pSftpDLL, nError, pBuf2, @i)
_dOut(pBuf2)

i := Sftp_Connect(pSftpDLL)

// Eine Schleife um die Events zu testen.
DO WHILE nCount <= 100
// nRet := Sftp_GetState(pSftpDLL, @nState)
// _dOut(nState)
// IF nState==3
// EXIT
// ENDIF
// ApplicationExec(EXECWHILEEVENT)
DoEvents()
Sleep(100)
nCount++
ENDDO

nRet := Sftp_GetState(pSftpDLL, @nState)
_dOut(nState)

IF nState == 3
// IF i == 0
nRet := Sftp_GetState(pSftpDLL, @nState)

nRet := Sftp_ListAttributes(pSftpDLL, String2Psz("/home/longtest"))
i := 10240
nRet := Sftp_GetListItem(pSftpDLL, pBuf1, @i)
_dOut(pBuf1)
SaveFile("sftp_dir_1.txt", Psz2String(pBuf1))

nRet := Sftp_PutFile(pSftpDLL, String2Psz("C:\MyTest\TestFile.txt"), String2Psz("/home/longtest"))

nRet := Sftp_ListAttributes(pSftpDLL, String2Psz("/home/longtest"))
i := 10240
nRet := Sftp_GetListItem(pSftpDLL, pBuf1, @i)
_dOut(pBuf1)
SaveFile("sftp_dir_2.txt", Psz2String(pBuf1))
ELSE
nRet := Sftp_GetLastError(pSftpDLL, @nError)
i := 1024
nRet := Sftp_GetErrorText(pSftpDLL, nError, pBuf2, @i)
_dOut(pBuf2)
ENDIF
nRet := Sftp_Disconnect(pSftpDLL)
Sftp_Destroy(pSftpDLL)

MemFree(pBuf1)
MemFree(pBuf2)

RETURN NIL

Rüdiger Fresemann

unread,
Jan 24, 2022, 9:01:31 AMJan 24
to
Super, danke dir!
Ich werde das mal in Ruhe testen und gebe dir dann Rückmeldung.

LG Rüdiger

Rüdiger Fresemann

unread,
Jan 24, 2022, 2:52:33 PMJan 24
to
Hallo Gerhard,

Jetzt musst du mir doch nochnmal helfen.

Ich habe deinen Code probiert, aber ich bekomme immer einen Fehler: "Der
Prozedureinsprungspunkt wurde nicht gefunden....."

Wahrscheinlich lädt er die DLL nicht richtig. Kannst du mir da noch
einen Tipp geben?

Rüdiger

Gerhard Bunzel

unread,
Jan 25, 2022, 9:32:15 AMJan 25
to
Hallo Rüdiger,

ist die Datei SftpDLL.dll im gleichen Verzeichnis wie die EXE-Datei?

Gerhard

Rüdiger Fresemann

unread,
Jan 26, 2022, 2:34:27 AMJan 26
to
Hallo Gerhard,

Ich glaube, ich habs gefunden. Ich denke, du benutzt ein anderes Produkt
wie ich. Bei mir heißt die DLL wodSFTP.dll und ist von WeOnlyDo.

So What, ich habe einen anderern Weg gefunden:

- Die DLL wird über regsvr32 in Windows registriert.
- Nun kann ich die DLL über OLEAutoObject in Cavo einbinden.
- Ich erreiche nun alle Funktionen bequem, außer die Events.
- Die wichtigen Funktionen, wo ich ein Event haben möchte habe ich in
einen ErrorBlock() gepackt und mir einen Exception Handler gebastelt.
- Durch die Handler-Parameter im Codeblock kann ich die Eventergebnisse
abfragen (etwas eingeschränkt, aber brauchbar)

So klappt es relativ gut mit wenig aufwand ohne Painter,
Automationserver oder sonst was. Das hält der Pflegeaufwand ebenfalls
gering.

Trotzdem Danke für deinen Code, ein paar interessante Ideen hat er für
mich dennoch enthalten.

Rüdiger

Gerhard Bunzel

unread,
Jan 26, 2022, 12:42:42 PMJan 26
to
Hallo Rüdiger,

>Bei mir heißt die DLL wodSFTP.dll und ist von WeOnlyDo.
Dann benutzt Du wodSFTP ActiveX component.
Ich benutze die in meinem Link angegebene wodSFTPdll - die DLL-Version davon.

Der Vorteil der DLL-Version ist nach meiner Meinung, die muss nicht installiert werden - einfach in das Programmverzeichnis kopieren - fertig.
Keine Installation - keine Registrierung der DLL. Auch wenn der User keine Installationsrechte hat, kann die Funktion genutzt werden.

Gerhard
Reply all
Reply to author
Forward
0 new messages