How can I use the components from C?

Write a plain C program using the C++ Edition components. Yes, it is possible.

Date Entered: 6/17/2004    Last Updated: 07/13/2017

Introduction

The C++ Editions provide support for plain C as we export plain C interfaces with header files that wrap them into C++. In the header files located in the "include" folder of your installation directory you will find the function definitions (as well as other information like events) that you will need to call from your C program. For instance in the sftp.h file included in IPWorks SSH V8:

extern "C" void* IPWORKSSSH_CALL SFTP_Create(PIPWORKSSSH_CALLBACK lpSink, void *lpContext, char *lpOemKey); extern "C" int IPWORKSSSH_CALL SFTP_Destroy(void *lpObj); extern "C" int IPWORKSSSH_CALL SFTP_CheckIndex(void *lpObj, int propid, int arridx); extern "C" void* IPWORKSSSH_CALL SFTP_Get(void *lpObj, int propid, int arridx, int *lpcbVal); extern "C" int IPWORKSSSH_CALL SFTP_Set(void *lpObj, int propid, int arridx, const void *val, int cbVal); extern "C" int IPWORKSSSH_CALL SFTP_Do(void *lpObj, int methid, int cparam, void *param[], int cbparam[]); extern "C" char* IPWORKSSSH_CALL SFTP_GetLastError(void *lpObj); extern "C" int IPWORKSSSH_CALL SFTP_GetLastErrorCode(void *lpObj); extern "C" int IPWORKSSSH_CALL SFTP_StaticInit(void *hInst);

Defining Methods, Properties, Events, and Types

A component's events, properties, methods, and any types will also have to be explicitly defined as constants within the context of your program.

#define EVENT_CONNECTED (1) ... #define PROP_DIRLISTCOUNT (2) ... #define METHOD_LISTDIRECTORY (8) ... #define SSHAUTHMODE_PASSWORD (2)
Each property and method has its own index, which can be determined by viewing the C++ wrapper calls. Then in the case that a property call requires an array index (arridx parameter) or data length (*lpcbVal parameter), these parameters can be set as necessary. For some items, like event parameters, we will also have to give type definitions. For instance with our SFTP program we would define the Connected event parameters like this:

typedef struct { int StatusCode; const char* Description; int reserved; } SFTPConnectedEventParams;
And lastly, remember the function definitions we saw in the header files? We will also have to define them in our plain C program (because we aren't going to use the header files). That would look like:

void* IPWORKSSSH_CALL SFTP_Create(PIPWORKSSSH_CALLBACK lpSink, void *lpContext, char *lpOemKey); int IPWORKSSSH_CALL SFTP_Destroy(void *lpObj); int IPWORKSSSH_CALL SFTP_CheckIndex(void *lpObj, int propid, int arridx); void* IPWORKSSSH_CALL SFTP_Get(void *lpObj, int propid, int arridx, int *lpcbVal); int IPWORKSSSH_CALL SFTP_Set(void *lpObj, int propid, int arridx, const void *val, int cbVal); int IPWORKSSSH_CALL SFTP_Do(void *lpObj, int methid, int cparam, void *param[], int cbparam[]); char* IPWORKSSSH_CALL SFTP_GetLastError(void *lpObj); int IPWORKSSSH_CALL SFTP_GetLastErrorCode(void *lpObj); int IPWORKSSSH_CALL SFTP_StaticInit(void *hInst);

Implementing Events

When you call the SFTP_Create method, the "SFTP_CALLBACK lpSink" method is the callback function used to fire events through. The SFTPEventSink method within the header file contains the available event types, IDs, and parameters. Therefore you should be able to add/implement the SFTPEventSink method within your application to handle events. If you wish, instead of actually creating/implementing the Fire*** methods you can just use the switch statement within SFTPEventSink (so in other words you will not need to create all the EventParams structs). For example:

static int IPWORKSSSH_CALL SFTPEventSink(void *lpObj, int event_id, int cparam, void *param[], int cbparam[]) { int ret_code = 0; switch (event_id) { case EVENT_CONNECTED: { SFTPConnectedEventParams e = {(int)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), 0}; break; } case EVENT_CONNECTIONSTATUS: { SFTPConnectionStatusEventParams e = {(char*)IPH64CAST(param[0]), (int)IPH64CAST(param[1]), (char*)IPH64CAST(param[2]), 0}; break; } } return ret_code; }

Calling Methods and Setting Properties

Later in your program you can call the functions we have defined. For example to set the SSHUser property on an SFTP component:

SFTP_Set(m_pObj, PROP_SSHUSER, 0, (void*)"USER", 0);

Compilation

You can compile on a Unix/Linux system or on Windows just like any other C program. For Unix/Linux a good choice is gcc/g++. On Windows, Visual Studio includes a C compiler by the name of cl.exe which you can find in YourVSDirectory/VC/bin. Make sure to compile with a reference to the library you are using. Compiling our SFTP program on Windows could look like this:

cl.exe /Tc .\sftp_demo.c .\ipworksssh8.lib

Full Example

Now that we have covered some of the individual pieces of using the C++ Edition components in C, we can have a look at a whole program as an example. This example is a simple SFTP client.

#include /*** DEFINE ***/ #define IPWORKSSSH_CALL __stdcall // Comes from ipworksssh.h #define IPH64CAST (ns_int64) // Comes from ipworksssh.h // Event constants #define EVENT_CONNECTED (1) #define EVENT_CONNECTIONSTATUS (2) #define EVENT_DIRLIST (3) #define EVENT_DISCONNECTED (4) #define EVENT_ENDTRANSFER (5) #define EVENT_ERROR (6) #define EVENT_SSHKEYBOARDINTERACTIVE (7) #define EVENT_SSHSERVERAUTHENTICATION (8) #define EVENT_SSHSTATUS (9) #define EVENT_STARTTRANSFER (10) #define EVENT_TRANSFER (11) #define PROP_DIRLISTCOUNT (2) #define PROP_DIRLISTENTRY (3) #define PROP_DIRLISTFILENAME (4) #define PROP_DIRLISTFILESIZE (5) #define PROP_DIRLISTFILETIME (6) #define PROP_DIRLISTISDIR (7) #define PROP_LOCALFILE (29) #define PROP_REMOTEFILE (33) #define PROP_REMOTEPATH (34) #define PROP_SSHAUTHMODE (36) #define PROP_SSHHOST (44) #define PROP_SSHPASSWORD (45) #define PROP_SSHPORT (46) #define PROP_SSHUSER (47) #define METHOD_DOEVENTS (5) #define METHOD_LISTDIRECTORY (8) #define METHOD_SSHLOGOFF (14) #define METHOD_SSHLOGON (15) #define SSHAUTHMODE_PASSWORD (2) /*** END DEFINE ***/ /**** TYPEDEFS ****/ typedef long int ns_int64; // Comes from ipworksssh.h typedef unsigned long int ns_uint64; // Comes from ipworksssh.h typedef struct { int StatusCode; const char* Description; int reserved; } SFTPConnectedEventParams; typedef struct { const char* ConnectionEvent; int StatusCode; const char* Description; int reserved; } SFTPConnectionStatusEventParams; typedef struct { const char* DirEntry; const char* FileName; int IsDir; ns_int64 *pFileSize; const char* FileTime; int reserved; } SFTPDirListEventParams; typedef struct { int StatusCode; const char* Description; int reserved; } SFTPDisconnectedEventParams; typedef struct { int Direction; int reserved; } SFTPEndTransferEventParams; typedef struct { int ErrorCode; const char* Description; int reserved; } SFTPErrorEventParams; typedef struct { const char* Name; const char* Instructions; const char* Prompt; const char* Response; int EchoResponse; int reserved; } SFTPSSHKeyboardInteractiveEventParams; typedef struct { const char* HostKey; const char* Fingerprint; const char* KeyAlgorithm; int Accept; int lenHostKey; int reserved; } SFTPSSHServerAuthenticationEventParams; typedef struct { const char* Message; int reserved; } SFTPSSHStatusEventParams; typedef struct { int Direction; int reserved; } SFTPStartTransferEventParams; typedef struct { int Direction; ns_int64 *pBytesTransferred; int PercentDone; const char* Text; int lenText; int reserved; } SFTPTransferEventParams; /**** END TYPEDEFS ****/ typedef int (IPWORKSSSH_CALL *PIPWORKSSSH_CALLBACK) (void *lpObj, int event_id, int cparam, void *param[], int cbparam[]); /*** FUNCTION DEFINITIONS ***/ void* IPWORKSSSH_CALL SFTP_Create(PIPWORKSSSH_CALLBACK lpSink, void *lpContext, char *lpOemKey); int IPWORKSSSH_CALL SFTP_Destroy(void *lpObj); int IPWORKSSSH_CALL SFTP_CheckIndex(void *lpObj, int propid, int arridx); void* IPWORKSSSH_CALL SFTP_Get(void *lpObj, int propid, int arridx, int *lpcbVal); int IPWORKSSSH_CALL SFTP_Set(void *lpObj, int propid, int arridx, const void *val, int cbVal); int IPWORKSSSH_CALL SFTP_Do(void *lpObj, int methid, int cparam, void *param[], int cbparam[]); char* IPWORKSSSH_CALL SFTP_GetLastError(void *lpObj); int IPWORKSSSH_CALL SFTP_GetLastErrorCode(void *lpObj); int IPWORKSSSH_CALL SFTP_StaticInit(void *hInst); static int IPWORKSSSH_CALL SFTPEventSink(void *lpObj, int event_id, int cparam, void *param[], int cbparam[]) { int ret_code = 0; switch (event_id) { case EVENT_CONNECTED: { SFTPConnectedEventParams e = {(int)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), 0}; break; } case EVENT_CONNECTIONSTATUS: { SFTPConnectionStatusEventParams e = {(char*)IPH64CAST(param[0]), (int)IPH64CAST(param[1]), (char*)IPH64CAST(param[2]), 0}; break; } case EVENT_DIRLIST: { SFTPDirListEventParams e = {(char*)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), (int)IPH64CAST(param[2]), (ns_int64*)IPH64CAST(param[3]), (char*)IPH64CAST(param[4]), 0}; break; } case EVENT_DISCONNECTED: { SFTPDisconnectedEventParams e = {(int)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), 0}; break; } case EVENT_ENDTRANSFER: { SFTPEndTransferEventParams e = {(int)IPH64CAST(param[0]), 0}; break; } case EVENT_ERROR: { SFTPErrorEventParams e = {(int)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), 0}; break; } case EVENT_SSHKEYBOARDINTERACTIVE: { SFTPSSHKeyboardInteractiveEventParams e = {(char*)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), (char*)IPH64CAST(param[2]), (char*)IPH64CAST(param[3]), (int)IPH64CAST(param[4]), 0}; param[3] = (void*)(e.Response); break; } case EVENT_SSHSERVERAUTHENTICATION: { SFTPSSHServerAuthenticationEventParams e = {(char*)IPH64CAST(param[0]), (char*)IPH64CAST(param[1]), (char*)IPH64CAST(param[2]), (int)IPH64CAST(param[3]), (int)IPH64CAST(cbparam[0]), 0}; e.Accept = 1; // true param[3] = (void*)(e.Accept); break; } case EVENT_SSHSTATUS: { SFTPSSHStatusEventParams e = {(char*)IPH64CAST(param[0]), 0}; break; } case EVENT_STARTTRANSFER: { SFTPStartTransferEventParams e = {(int)IPH64CAST(param[0]), 0}; break; } case EVENT_TRANSFER: { SFTPTransferEventParams e = {(int)IPH64CAST(param[0]), (ns_int64*)IPH64CAST(param[1]), (int)IPH64CAST(param[2]), (char*)IPH64CAST(param[3]), (int)IPH64CAST(cbparam[3]), 0}; break; } } return ret_code; } void *m_pObj; int main() { int ret_code = 0; int index; m_pObj = SFTP_Create(SFTPEventSink, (void*)m_pObj, (char*)"my_string"); SFTP_Set(m_pObj, PROP_SSHHOST, 0, (void*)"SERVER_HOST_NAME", 0); SFTP_Set(m_pObj, PROP_SSHPORT, 0, (void*)22, 0); SFTP_Set(m_pObj, PROP_SSHAUTHMODE, 0, (void*)SSHAUTHMODE_PASSWORD, 0); SFTP_Set(m_pObj, PROP_SSHUSER, 0, (void*)"USER", 0); SFTP_Set(m_pObj, PROP_SSHPASSWORD, 0, (void*)"PASSWORD", 0); ret_code = SFTP_Do(m_pObj, METHOD_LISTDIRECTORY, 0, 0, 0); for (index = 0; index < (int)(long)SFTP_Get(m_pObj, PROP_DIRLISTCOUNT, 0, 0); index++) { printf("%s\n", (char*)SFTP_Get(m_pObj, PROP_DIRLISTENTRY, index, 0)); } if (ret_code) { printf(SFTP_GetLastError(m_pObj)); } getchar(); return 0; }

We appreciate your feedback.  If you have any questions, comments, or suggestions about this entry please contact our support team at kb@nsoftware.com.