C# TaskCompleted Event — Updating the UI from a Background Thread

This sample C# snippet demonstrates how to use the TaskCompleted event to be notified when an asynchronous method completes. Given that the event callback is in the background thread, any UI updates must occur on the main thread. This example demonstrates how to do it:

	private void taskCompletedToolStripMenuItem_Click(object sender, EventArgs e)
	    {
	    // Demonstrate an asynchronous Chilkat method call with a TaskCompleted event.
	    Chilkat.Http http = new Chilkat.Http();

	    http.OnTaskCompleted += http_OnTaskCompleted;

	    Chilkat.Task task = http.QuickGetStrAsync("http://www.chilkatsoft.com/");

	    // We can set the task.UserData property to identify this particular asynchronous call in the callback.
	    task.UserData = "chilkatHomePage";

	    // Runs the HTTP GET asynchronously on a background thread..
	    task.Run();
	    }

	// This event fires in the background thread. 
	// 
	void http_OnTaskCompleted(object sender, Chilkat.TaskCompletedEventArgs args)
	    {
	    Chilkat.Task task = args.Task;

	    // This event callback is running in the background thread.
	    // To update a UI element, we must be on the UI thread..
	    this.Invoke((MethodInvoker)delegate
		{
		    // The task.UserData can be used to identify the particular asynchronous method call
		    // that this callback belongs to.
		    if (task.UserData.Equals("chilkatHomePage"))
			{
			// An asychronous method is simply calling the corresponding synchronous method
			// in a background thread.  In this case, it is a call to QuickGetStr,
			// which returned a string, or it returned Nothing for failure.  This result is available
			// via task.GetResultString.  The LastErrorText for the background call 
			// is available in task.ResultErrorText
			string htmlPage = task.GetResultString();
			if (htmlPage == null)
			    {
			    textBox2.Text = task.ResultErrorText;
			    }
			else
			    {
			    textBox2.Text = htmlPage;
			    }
			}
		});
	    }
	}

(C++) Return Email Headers as iso-8859-15? (or any other charset)

Question:

In C++, is it somehow possible to specify a desired charset (like ISO-8859-15) when getting mail headers with POP3?

Answer:

Instead of calling the method that returns a “const char *” — which can return either utf-8 or ANSI (see this Chilkat blog post about the Utf8 property common to all Chilkat C++ classes), call the alternate method that returns the string in a CkString object.  You can then get the iso-8859-15 string from the CkString object.

Each Chilkat C++ method that returns a string has two versions — an upper-case version that returns the string in a CkString (always the last argument), and a lower-case version that returns a “const char *”.

For example, in the CkEmail class:

bool GetHeaderField(const char *fieldName, CkString &outFieldValue);
const char *getHeaderField(const char *fieldName);

The lower-case method returning a “const char *” returns a pointer to memory that may be overwritten in subsequent calls.  Therefore, make sure to copy the string to a safe place immediately before making additional calls on the same Chilkat object instance.  (Only methods that also return “const char *” would overwrite the memory from a previous call.)

The upper-case version of the method returns the string in a CkString object.  It is an output-only argument, meaning that the CkString contents are replaced, not appended.  To get the iso-8859-15 string from the CkString, call the getEnc method.  For example:

const char  *str_iso_8859_15 = outFieldValue.getEnc("iso-8859-15");

This returns a NULL-terminated string where each character is represented as a single byte using the iso-8859-15 encoding.

Chilkat C/C++ libraries now available for MAC OS X

The Chilkat C/C++ libraries are now available for MAC OS X. For the download link and more information, see http://www.chilkatsoft.com/installMacOSX.asp

Chilkat will soon release MAC OS X compatible builds for Java, Perl, Python, and Ruby. Following that, builds for the IOS (IPhone) will be released, along with Objective-C/C++ native libraries for both MAC OS X and IPhone.

Very simple C# SSH Shell Console Terminal

Here’s an example that demonstrates a rough start to creating a C# console SSH shell terminal (where the user can type commands and output from the remote command echos to the console:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace SshTerminalConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Chilkat.Ssh ssh = new Chilkat.Ssh();
            ssh.UnlockComponent("Test");

            //  Hostname may be an IP address or hostname:
            string hostname = "192.168.1.117";
            int port = 22;

            Console.WriteLine("Connecting...");

            //ssh.KeepSessionLog = true;
            bool success = ssh.Connect(hostname, port);
            if (success != true)
            {
                Console.WriteLine(ssh.LastErrorText + "\r\n");
                // Read so we can see the error before the console closes.
                string x = Console.ReadLine();      
                return;
            }

            //  When reading, if no additional data arrives for more than
            //  5 seconds, then abort:
            ssh.IdleTimeoutMs = 5000;

            Console.WriteLine("Authenticating...");

            //  SSH Server Authentication
            //  If there is no login/password required, you must still call
            //  AuthenticatePw and use any values for login/password.
            success = ssh.AuthenticatePw("chilkat", "***");
            if (success != true)
            {
                Console.WriteLine(ssh.LastErrorText + "\r\n");
                // Read so we can see the error before the console closes.
                string x = Console.ReadLine();
                return;
            }

            Console.WriteLine("Opening Channel...");

            //  Open a session channel.
            int channelNum = ssh.OpenSessionChannel();
            if (channelNum < 0)
            {
                Console.WriteLine(ssh.LastErrorText + "\r\n");
                // Read so we can see the error before the console closes.
                string x = Console.ReadLine();
                return;
            }

            //  Request a pseudo-terminal
            string termType;
            termType = "dumb";
            int widthInChars;
            widthInChars = 120;
            int heightInChars;
            heightInChars = 40;
            int pixWidth;
            pixWidth = 0;
            int pixHeight;
            pixHeight = 0;
            success = ssh.SendReqPty(channelNum, termType, widthInChars, heightInChars, pixWidth, pixHeight);
            if (success != true)
            {
                Console.WriteLine(ssh.LastErrorText + "\r\n");
                // Read so we can see the error before the console closes.
                string x = Console.ReadLine();
                return;
            }

            Console.WriteLine("Starting a shell...");

            //  Start a shell on the channel:
            success = ssh.SendReqShell(channelNum);
            if (success != true)
            {
                Console.WriteLine(ssh.LastErrorText + "\r\n");
                // Read so we can see the error before the console closes.
                string x = Console.ReadLine();
                return;
            }

            // Loop to read from the SSH channel, output to the console, and read keyboard input from the console.
            StringBuilder sb = new StringBuilder();
            while (true)
            {
                if (Console.KeyAvailable)
                {
                    ConsoleKeyInfo key = Console.ReadKey(true);
                    Console.Write(key.KeyChar);

                    switch (key.Key)
                    {
                        case ConsoleKey.Enter:
                            Console.WriteLine("");

                            sb.Append("\n");
                            success = ssh.ChannelSendString(channelNum, sb.ToString(), "ansi");
                            if (success != true)
                            {
                                Console.WriteLine(ssh.LastErrorText + "\r\n");
                                // Read so we can see the error before the console closes.
                                string x = Console.ReadLine();
                                return;
                            }

                            sb.Length = 0;
                            break;
                        default:
                            //Console.Write(key.KeyChar);
                            sb.Append(key.KeyChar);
                            break;
                    }

                }

                // Now check for incoming data from the SSH channel.
                int retval = ssh.ChannelPoll(channelNum, 10);
                if (retval == -1)
                {
                    Console.Write(ssh.LastErrorText);
                    Console.WriteLine("");
                    // Read so we can see the error before the console closes.
                    string x = Console.ReadLine();
                    return;
                }
                if (retval > 0)
                {
                    Console.Write(ssh.GetReceivedText(channelNum, "ansi"));
                }
                else
                {
                    // If data arrived, loop around and get more immediately.
                    // Otherwise wait 20ms.
                    System.Threading.Thread.Sleep(20);
                }

            }  

        }
    }
}

Aborting in C++

The technique for aborting any time-consuming Chilkat C++ method call follows this recipe:

  1. Declare your own class that derives from the appropriate Chilkat progress monitoring class.  For CkMailMan it is CkMailProgress (as shown below).  For other Chilkat classes it is CkHttpProgress, CkFtpProgress, CkImapProgress, CkZipProgress, etc.
  2. Create an implementation for the AbortCheck method.  This will override the default implementation from the base class.  (The default implementation simply does nothing.)
  3. The AbortCheck method is called periodically according to the value of the HeartbeatMs property.  The default value of HeartbeatMs is 0, which indicate that no AbortCheck events should be called.  Set HeartbeatMs to a non-zero value (in milliseconds) to enable the AbortCheck callbacks.  Do this by calling put_HeartbeatMs(someValue)  as shown below.
  4. Whenever your application wishes to abort an operation in progress (SMTP, POP3, IMAP, Zip, FTP, etc.), set the abort boolean argument of AbortCheck to true.
  5. Don’t forget to hookup your event monitoring class by calling the SetProgressCallback method.  (See the code example below.)  In some classes, such as for CkImap, the way to hookup the event class is via the put_EventCallbackObject function.  Please review the .h file for details.
#include <CkMailProgress.h>

class MyMailProgress : public CkMailProgress
    {
    public:
	MyMailProgress(void) { }
	virtual ~MyMailProgress(void) { }

	// Override the AbortCheck method (which is a virtual method in CkMailProgress)
	// Called periodically according to the value of the HeartbeatMs property.
	void AbortCheck(bool *abort)
	    {
	    printf("AbortCheck!\n");

	    // If your application wishes to abort the email sending/receiving operation,
	    // set the abort boolean like this:
	    *abort = true;
	    }

        // Percentage completion events may also be overridden to abort time-consuming operations.
	void SendPercentDone(long pctDone, bool *abort) 
	    { 
	    printf("SendPercentDone: %d percent\n",pctDone);
	    }
	void ReadPercentDone(long pctDone, bool *abort) 
	    { 
	    printf("ReadPercentDone: %d percent\n",pctDone);
	    }

    };

void AbortCheckDemo(void)
    {
    CkMailMan mailman;
    bool success;
    success = mailman.UnlockComponent("30-day trial");
    if (success != true)
	{
        printf("%s\n",mailman.lastErrorText());
        return;
	}

    // Set the HeartbeatMs property so that AbortCheck is called once every 80 milliseconds.
    mailman.put_HeartbeatMs(80);

    MyMailProgress myProgress;
    mailman.SetProgressCallback(&myProgress);

    CkEmail email;
    // ...
    // ...

    // The AbortCheck event is called periodically while SendEmail is in progress..
    // (Note: In some cases, including here, a percent-done event is also called, and it will have an "abort"
    // boolean argument that may be set to "true" to force an abort.
    // If the percent-done callbacks happen more frequently than the HeartbeatMs setting, then 
    // the AbortCheck events may not be fired at all.)
    success = mailman.SendEmail(email);
    if (success != true)
	{
        printf("%s\n",mailman.lastErrorText());
        return;
	}

    }

Socket SendString (C++) w/ TCHAR

Question:

I need to send a unicode string (e.g TCHAR *ptr) but the API only allows to send char.

Answer:

/*
The _TCHAR data type is defined conditionally in Tchar.h. 
If the symbol _UNICODE is defined for your build, _TCHAR is defined as wchar_t; 
otherwise, for single-byte and MBCS builds, it is defined as char.
*/
bool sendString(CkSocket &sock, TCHAR *str)
    {
    bool success = false;

#ifdef _UNICODE
    success = sock.SendBytes((const unsigned char *)str, _tcslen(str) * 2);
#else
    success = sock.SendString(str);
#endif

    return success;
    }

Is Calling .Dispose() Recommended for C# and VB.NET?

Question:

In your examples online, we have noticed that .Dispose() is never
called after using Chilkat classes (we are writing in C#).

Is calling .Dispose() recommended?  Does your code not need to destroy
any native resources or handles that would normally be cleaned up in
the Dispose method (the IDisposeable interface) ?

Answer:

For objects that manage a TCP/IP socket connection with a server (FTP2, SSH, SFTP, POP3, SMTP, IMAP, HTTP, etc.) then calling Dispose will close the connection.  Aside from memory-usage and socket connections, there are no other resources used by Chilkat classes.  Dispose may also deallocate some internal memory.

The important thing to realize is that once Dispose is called, your code should not use that particular instance of the object again.  I always prefer a more explicit approach.  For example, instead of calling Chilkat.MailMan.Dispose to ensure that a connection to the SMTP server is closed, call Chilkat.MailMan.CloseSmtpConnection.  (If the mailman is not actually connected, calling CloseSmtpConnection does NOT result in an error.  It is harmless.)

Also, when an Chilkat object’s finalizer is called (i.e. when it is garbage-collected), any existing socket connections are closed and internal memory is (of course) deallocated.   You may force garbage collection by doing this (in C#)

 GC.Collect();
 GC.WaitForPendingFinalizers();

Chilkat C++ Libs – Link and Maintain Single EXE?

Question:

I am developing a single EXE in C++ that doesn’t make use of any external libraries and including MFC. Can I add your zip libaries to my application and still maintain the application as a single EXE?

Answer:

Yes, the Chilkat C++ libs may be linked directly into your application.  This results in a single EXE containing the Chilkat library code required to satisfy all direct and indirect references.  (The linker includes only the code needed to resolve all references.)  You may run your EXE on any computer because the licensing is royalty-free.  Internally, Chilkat does not use or reference MFC.   (Note: MFC applications may still use the Chilkat libs.  The point is this: if your application does not use MFC, then linking with Chilkat will not cause MFC to be “pulled-into” your EXE.)