| Java | ||
|
The SocketTools Library Edition provides a Java package which can be included with your projects. The package is named SocketTools and can be found in the Java folder where you've installed the product. It includes wrapper classes for each of the libraries, as well as all of the constants and error codes. It also defines some standard Windows API functions which can be helpful when using some of the methods. To use the package in Visual J++, you need to open the Properties for your project, select the Classpath tab and add the SocketTools.zip file to the project. The Library Edition also includes a Visual J#.NET package named SocketTools which can be found in the Include folder where you've installed the product. The file name is Cstools5.jsl and the implementation is very similar to the Java classes, however it uses some .NET specific features. To use the package in J#, simply add it to the project. One of the first things you will notice is that the Java implementation is somewhat different than the standard API. The client handles are defined as integers, and many of the functions use the String and StringBuffer classes rather than the typical pointer to an array of characters found in C/C++. In addition, the function names themselves have been changed slightly and the names of constants have been changed to be more consistent with Java naming conventions. The function names have been altered so that in most cases the protocol name which prefixes the function has been removed. For example, the Hypertext Transfer Protocol library has a function called HttpGetData. The equivalent function in Java would be called as HttpClient.GetData. The function FtpPutFile would be called as FtpClient.PutFile and so on. In addition, constants have been changed from all upper-case to mixed case names defined either in the Constants class, or the specific protocol class. For example, instead of using the constant FTP_ERROR, you would use FtpClient.ftpError instead. For programmers using Visual J++ or Visual J#.NET, it is recommended that you review the class source files which are included with the product. The SocketTools Java classes use J/Direct and the @dll.import attribute to define the class methods. If you are using Visual J++, this means that you must open the Properties for your project, select the Compile tab and uncheck the "Disable Microsoft Language Extensions" checkbox. If you don't do this, you'll get a warning that the @dll directive was ignored. String ArgumentsThere are a few special considerations that programmers should be aware of when using string buffers that are passed by reference and modified by the function. An example of this would be the GetErrorString function, which is used to obtain a description of a specific error. In C/C++ you would allocate a character array and pass it to the function, such as: TCHAR szError[256]; DWORD dwError; INT nLength; dwError = HttpGetLastError(); nLength = HttpGetErrorString(dwError, szError, 256); MessageBox(NULL, szError, "Error", MB_OK | MB_ICONEXCLAMATION); In Java the GetErrorString function in the HttpClient class uses the StringBuffer class as the string argument. The equivalent code would be: StringBuffer strError = new StringBuffer(256); int nError; int nLength; nError = HttpClient.GetLastError(); nLength = HttpClient.GetErrorString(nError, strError, 256); MessageBox.Show(strError.toString(), "Error"); Keep in mind that if you want to pass a StringBuffer variable to a function that expects a String, you should use the toString method. Byte Array ArgumentsA number of SocketTools functions use byte arrays, either as an input argument to the function, or as an output argument which will contain data when the function returns. An example of this is the HttpGetData function, which will access a resource on the server and return the contents of that resource in a byte array passed to the function. For example, the following code in C++ would return the first 1024 bytes of the index page on a webserver:
If the function is successful, the byteBuffer array will contain the first 1024 bytes of the index page. In Java, the equivalent code would look like this:
Because the dwLength parameter is passed by reference in C++ and Java doesn't support pointers, you'll need to create an array and pass that as the argument. In addition, to convert the byte array into a string, you will need to use the String class. For example: String strBuffer = new String(byteBuffer, 0, cbBuffer); This would convert the contents of the byte array into a String. Note that you should only do this if the data returned by the function is actually text. In this example, it is acceptable to do because the byte array contains the HTML text for the index page. Global Memory HandlesIn addition to using byte arrays, some SocketTools functions can use global memory handles (HGLOBALs) to exchange large amounts of data. Using the Windows API, global memory handles are allocated by the GlobalAlloc function, dereferenced by the GlobalLock function and released by the GlobalFree function. These handles can be used with the helper functions defined in the SocketTools.Win32 class which can be used to dereference and release global memory handles. An application may choose to use a global memory handle instead of a pre-allocated buffer if the amount of data is very large, or the total amount of data that will be returned is unknown at the time the function is being called. Consider the call to the GetData method used in the previous example. A pre-allocated buffer of 1024 bytes was passed to the function, and it copied up to that amount of data into the buffer. However, what if you wanted the complete page and did not know how large it was? You could attempt to determine the size of the page that was being requested using the GetFileSize method, and then use that value to allocate a buffer. However, this incurs additional overhead and it is not always possible to get the size of a resource on a web server. Another alternative would be to simply allocate a very large buffer, but this could result in the application allocating large amounts of memory that it doesn't use and you would still run the risk that it wouldn't be large enough. The solution for this problem is to use a global memory handle rather than a pre-allocated buffer. Instead of copying the data into a buffer, the function allocates a global memory handle and stores the contents in the memory referenced by that handle. When the function returns, it passes the handle back to the caller. The caller then dereferences the handle to access the memory, and releases the handle when it is no longer needed. Here is an example of how it would be used in C/C++:
Note that the global memory handle is initialized to NULL and the length argument is initialized to zero. This is important to do because this is how the function knows that it should be returning a global memory handle instead of copying data into a buffer. If you forget to initialize those arguments, the function will fail and may cause the application to terminate with a general protection fault. The equivalent code in Java would look like this:
It is important to remember to unlock and release the global memory handle when you are no longer using it. Those handles are not managed by the garbage collector, so if you forget to release them, the application will have a memory leak. Event Handlers in Visual J++SocketTools uses events to notify the application when some change in status occurs, such as when data is available to be read. An event handler is simply a callback function which has a specific set of arguments, and the address of that function is passed to the RegisterEvent function in the library. However, Java doesn't permit you to simply pass the address of a function in the same way that you can in C/C++. If you are using Visual J++ then event handlers are implemented by creating a class which extends the SocketTools.EventCallback class. The class must have a method named callback, and the event code is written inside that method. In C/C++, the callback function would be declared as:
In Java, the event handler would be declared inside the class as:
Let's create an event handler that updates a progress bar as a file is being downloaded from a server. To do this, we'll create a private class:
This event handler checks to see if the event ID indicates that it is a progress event, and if it is, creates a TransferStatus structure and calls GetTransferStatus to determine the number of bytes which have been copied so far. This is used to calculate a percentage and a progress bar control is updated with that value. Now that the event handler has been written, the next step is to register the event in order to enable notification for that event:
The first argument to RegisterEvent is the handle to the client session. The second argument is the event ID for which you want to enable notification, the third argument is the event handler class, and the fourth argument is a user-defined value. That same value is passed to the event handler as the dwParam argument. Event Handlers in Visual J#.NET private void HttpEventHandler(int hClient, int nEventId, int dwError, int dwParam) First, we'll create an event handler that updates a progress bar as a file is being downloaded from the server:
This event handler checks to see if the event ID indicates that it is a progress event, and if it is, creates a TransferStatus structure and calls GetTransferStatus to determine the number of bytes which have been copied so far. This is used to calculate a percentage and a progress bar control is updated with that value. Now that the event handler has been written, the next step is to create the event delegate for the method. For each of the SocketTools networking libraries that support event notification, there is a delegate defined in the class called EventDelegate. The delegate is created using code like this:
The httpEventHandler variable is now like a function pointer which can be passed to RegisterEvent in order to enable notification for that event:
The first argument to RegisterEvent is the handle to the client session. The second argument is the event ID for which you want to enable notification, the third argument is the event delegate, and the fourth argument is a user-defined value. That same value is passed to the event handler as the dwParam argument. Your event handler is now registered, and SocketTools will call your event handler during the process of downloading or uploading a file to notify you of the progress of the transfer. |
||
|
Copyright © 2012 Catalyst Development Corporation. All rights reserved. |