Microsoft Visual C#  
 

The SocketTools ActiveX Edition components can be used with Visual C# much in the same way that the controls are used in Visual Basic. The easiest way to create an instance of the control is to add it to your toolbox and place it on a form. Simply select the Toolbox, and right-click on it to bring up a context menu, and then select Add/Remove Items. This will display the Customize Toolbox dialog. Select the COM Components tab, and scroll down to the control or controls that you wish to add, check them and click OK. Once the components have been added to your toolbox, you can drag and drop them on your form, which will add them to your project.

Another approach is to add the control to the project as a reference, rather than placing the control on a form. In the Solution Explorer, right click on References and select Add Reference. Then select the component from the list of COM objects and click OK. Once the control has been added to the project as a reference, an instance of the control can be created using the new operator.

Variants and Objects

The SocketTools component interface is essentially the same in C# as it is with other languages, however there are a few differences. In C#, variant data types are represented by the object type. This is important because all of the component methods and event arguments are typed as variants. This can lead to unexpected errors when developing your application. For example, consider this code:

int nError;
nError = axFtpClient1.Connect();

Because the Connect method returns a value which indicates success by returning a value of zero, or an error code, this code looks correct. However, if you would try to compile it, you would get an error message indicating that the compiler cannot implicitly convert type 'object' to type 'int'. This is because all of the methods in the SocketTools components return the value as a variant type, which in C# is represented as an object. To resolve this, all you need to do is simply cast the return value to an int type, such as:

int nError;
nError = (int)axFtpClient1.Connect();

Another common issue is that some of the methods in the SocketTools components expect arguments to be passed by reference, and the data is returned in the specified variable. An example of this is the GetDirectory method in the File Transfer Protocol control. The method expects a single argument, passed by reference. When the method returns, that argument will contain a string that specifies the current working directory. Because the method expects a variant type, you simply can't pass a string variable to the method. Instead, you need to use code like this:

object varDirectory = "";
int nError;

nError = (int)axFtpClient1.GetDirectory(ref varDirectory);
if (nError == 0)
{
    string strDirectory = varDirectory.ToString();
}

The varDirectory object is initialized to an empty string, and the ref keyword tells C# to pass the object by reference to the method. If the method returns a value of zero, which indicates success, then varDirectory contains the current working directory and that is assigned to a string variable.

Optional Arguments

Many of the methods in the SocketTools components use optional arguments which may be omitted if the caller wishes to use a default value. Unlike Visual Basic, C# requires that all arguments be specified. To omit an optional argument, use the special value Type.Missing as a placeholder. For example, the GetFile method in the FTP control expects four arguments, with the last two arguments being optional. The method could be called as follows:

nError = (int)axFtpClient1.GetFile(strLocalFile, strRemoteFile, Type.Missing, Type.Missing);

In this example, the GetFile method will use default values for the last two arguments. Note that this should only be used with those arguments which the documentation specifies as optional. If the argument is required and Type.Missing as passed as the value, a runtime exception will be thrown.

Property Names

In some cases, Visual C# will rename certain properties to avoid naming conflicts within the component class. The properties function in the same way, but the prefix 'Ctl' is added to the name. The two most common properties that this is done for are the Handle and State properties, renamed to CtlHandle and CtlState respectively. For the File Transfer Protocol control, the System property is also renamed to CtlSystem.

Note that these changes to the property names only occurs when the control is placed on a form, not when the control is added to the project as a reference.

Event Handlers

SocketTools uses events to notify the application when some change in status occurs, such as when data is available to be read or a command has been executed. To create an event handler, simply select the control, click on the Events button in the property browser and then double-click on the event. A new event handler will be added to your code. For example, if you choose the OnCommand event then code like this will be added:

private void axFtpClient1_OnCommand(object sender, AxFtpClientCtl._IFtpClientEvents_OnCommandEvent e)
{

}

If you are familiar with Visual Basic but new to C#, the first thing that you'll notice is that the arguments are not passed individually to the event. Instead, they are passed in the argument 'e', which is a class that encapsulates all of the event arguments. The technical reference shows that there are two arguments for the OnCommand event, ResultCode and ResultString. To access their values, you would write code like this:

private void axFtpClient1_OnCommand(object sender, AxFtpClientCtl._IFtpClientEvents_OnCommandEvent e)
{
    int nResult = (int)e.resultCode;
    string strResult = e.resultString.ToString();

    Console.WriteLine("{0}: {1}", nResult, strResult);
}

Note that the arguments passed to the event handler are variants, just as they are with methods. This means that in C# they are treated as the object type, and should be cast or explicitly converted to other intrinsic types.

Exception Handlers

When setting a property, it is possible that the control will generate an exception as a result of an error. If these exceptions are not handled in your application, it will cause the program to halt and display a dialog box. To handle an exception, use the try..catch statement, such as:

try 
{
    axFtpClient1.HostAddress = "abcd";
}
catch (System.Runtime.InteropServices.COMException ex)
{
    Console.WriteLine(ex.Message.ToString());
    return;
}

In this example, the HostAddress property is being set to an illegal value (the HostAddress property only accepts IP addresses in dot notation, such as "192.168.0.1"). As a result, an exception is thrown and the catch section of code is executed. The ex argument contains information about the exception that has occurred, including an error number and a description of the error. In this case, that description is written to the console and the function is exited.

In addition to exceptions generated when properties are set to invalid values, it is also possible to have methods generate exceptions instead of returning error codes. To do this, set the ThrowError property to true. It allows you to write code like this:

try
{
    axFtpClient1.ThrowError = true;
    axFtpClient1.Connect();
    axFtpClient1.ChangeDirectory(strDirName);
    axFtpClient1.ThrowError = false;
}
catch (System.Runtime.InteropServices.COMException ex)
{
    axFtpClient1.ThrowError = false;
    Console.WriteLine("Error {0}: {1}", ex.ErrorCode, ex.Message.ToString());

    if (axFtpClient1.IsConnected)
    {
        axFtpClient1.Disconnect();
    }
    return;
}

In this example, the ThrowError property is set to true, and then the Connect and ChangeDirectory methods are called. If either of these methods fail, an exception will be thrown and the code in the catch section will be executed. In this case, the error code and description is written to the console, the client is disconnected and the function returns. By setting the ThrowError property and writing your code to use exception handling, it enables you to easily group function calls together and handle any potential errors, rather than individually checking the return value for each method.