Posted to tcl by patthoyts at Wed Apr 08 14:10:37 GMT 2009view pretty

/* basethrd.c - Copyright (C) 2009 Pat Thoyts <patthoyts@users.sourceforge.net>
 *
 * Sample of an embedded Tcl application linked using the Tcl stubs mechanism
 * as seen at http://wiki.tcl.tk/2074.
 *
 * This version demonstrates linking to the stardll (ActiveTcl calls it a
 * basekit DLL) which is a TclKit presented as a DLL.
 *
 * This will create two threads and load a given basekit dll library on
 * each.
 *
 * can be built using:
 *  cl -MD -W3 -I/opt/tcl/include basethrd.c \opt\tcl\lib\tclstub85.lib
 *
 * ----------------------------------------------------------------------
 * This source code is public domain.
 * ----------------------------------------------------------------------
 *
 * $Id$
 */

#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#ifndef USE_TCL_STUBS
#define USE_TCL_STUBS
#endif
#include <tcl.h>

static Tcl_Interp *InitializeTcl(const char *dllname,int argc, char *args[]);

typedef struct Init {
    const char *path;
    int argc;
    char **argv;
    DWORD tid;
} Init;

DWORD WINAPI
BeginThread(LPVOID pClientData)
{
    Init *pInit = pClientData;
    Tcl_Interp *interp;
    int r = TCL_OK;

    interp = InitializeTcl(pInit->path, pInit->argc, pInit->argv);
    if (interp == NULL) {
	fprintf(stderr, "error: failed to initialize Tcl\n");
    } else {
	if (pInit->argc > 1) {
	    r = Tcl_EvalFile(interp, pInit->argv[1]);
	    printf(Tcl_GetStringResult(interp));
	}
	Tcl_DeleteInterp(interp);
    }
    return r;
}

int
main(int argc, char *argv[])
{
    HANDLE threads[2];
    Init init[2];
    int n;

    init[0].path = "basekit.dll";
    init[1].path = "basekit85.dll";

    for (n = 0; n < sizeof(threads)/sizeof(threads[0]); ++n)
    {
	init[n].argc = argc;
	init[n].argv = argv;

	threads[n] = CreateThread(0, 0, BeginThread, &init[n],
	    CREATE_SUSPENDED, &init[n].tid);
    }

    /* start the threads */
    for (n = 0; n < sizeof(threads)/sizeof(threads[0]); ++n)
	ResumeThread(threads[n]);

    while (1)
    {
	DWORD dwWait = WaitForMultipleObjects(n, threads, TRUE, 1000);
	if (dwWait == WAIT_TIMEOUT) {
	    printf("tick\n");
	} else if (dwWait >= WAIT_OBJECT_0 && dwWait < (WAIT_OBJECT_0 + n)) {
	    break;
	} else {
	    fprintf(stderr, "error!\n");
	    break;
	}
    }

    /* cleanup politely */
    for (n = 0; n < sizeof(threads)/sizeof(threads[0]); ++n)
	CloseHandle(threads[n]);
    
    return 0;
}

typedef Tcl_Interp * (*LPFNCREATEINTERP) ();
typedef int          (*LPFNBASEKITINIT)  (Tcl_Interp *);
typedef char *       (*LPFNSETKITPATH)   (char *);

Tcl_Interp *
InitializeTcl(const char *dllname, int argc, char *argv[])
{
    WCHAR szLibrary[MAX_PATH];
    CHAR  utfLibrary[MAX_PATH * 2];
    HINSTANCE hTcl = NULL;
    Tcl_Interp *interp = NULL;
    
    hTcl = LoadLibraryA(dllname);
    if (hTcl != NULL) {

        LPFNCREATEINTERP lpfnCreateInterp
            = (LPFNCREATEINTERP)GetProcAddress(hTcl, "Tcl_CreateInterp");
        LPFNBASEKITINIT lpfnBasekitInit 
            = (LPFNBASEKITINIT)GetProcAddress(hTcl, "TclKit_AppInit");
        LPFNSETKITPATH lpfnSetKitPath 
            = (LPFNSETKITPATH)GetProcAddress(hTcl, "TclKit_SetKitPath");

        if (lpfnCreateInterp != NULL && lpfnBasekitInit != NULL 
            && lpfnSetKitPath != NULL) 
        {
            interp = lpfnCreateInterp();
            if (interp != NULL) {
                Tcl_InitStubs(interp, "8.4", 0);
                Tcl_FindExecutable(argv[0]);
                GetModuleFileNameW(hTcl, szLibrary, MAX_PATH);
		WideCharToMultiByte(CP_UTF8, 0, szLibrary, -1, utfLibrary, MAX_PATH*2, NULL, NULL);
                lpfnSetKitPath(utfLibrary);
                if (lpfnBasekitInit(interp) == TCL_OK) {
                    Tcl_InitMemory(interp);
                } else {
                    fprintf(stderr, "TclKit_AppInit: %s\n",
                            Tcl_GetStringResult(interp));
                }
            }
        }
    }
    return interp;
}