Tcl_FSGetNativePath

TCL Library command to get a native path.

TCL 8.6.9 man page: [L1 ]

Error case

HaO2019-05-21: There is no official error case. Nevertheless, Ralf Fassel states on clt 2019-05-21 "Re: Passing file path with ß to C function from DLL":

While the manpage does not document it, looking at the TCL source code there are some code paths that return NULL, so one should check the returned value.

Windows DLL example

HaO2019-05-21: Adapted from Ralf Fassel on clt 2019-05-21 "Re: Passing file path with ß to C function from DLL", question by Alexandru Dadalau.

A C function should hash a file. The file path is specified from TCL. Platform is Windows. Here is a skeleton (untested, please edit directly):

// the following defines are important and should normally be given in the make file.
// To be sure that they are not forgotten, they are given here, accepting an eventual error of redefinition
#define USE_TCL_STUBS
#define UNICODE
#define _UNICODE
#define DLL_BUILD
#include <Windows.h>
#include <tchar.h>
#include "tcl.h"
int HashCmd(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
    wchar_t* fname;
    FILE * hFile;
    int hashValue;
    if (objc <= 1) {
        Tcl_WrongNumArgs(interp, 1, objv, "path");
        return TCL_ERROR;
    }
    // Get the native path as a UNICODE value from the function argument.
    fname = Tcl_FSGetNativePath(objv[1]);
    // Open the file in binary read mode
    if ( NULL == fname || NULL == (hFile = _wfopen(fname, L"rb"))) {
        Tcl_SetStringObj( Tcl_GetObjResult(interp), "Wrong file path",-1);
        return TCL_ERROR;
    }
    // ToDo:
    // do the hashing here into variable hashValue by reading from file handler hFile

    // Close the file handler
    fclose(hFile);
    // return the resulting hash value
    Tcl_SetIntObj( Tcl_GetObjResult(interp), hashValue);
    return TCL_OK;
}

// DLL entry point, not used here
BOOL __declspec(dllexport) WINAPI DllEntryPoint(HINSTANCE hInstance, DWORD seginfo, LPVOID lpCmdLine)
{
  return TRUE;
}

//  TCL setup when the DLL is loaded
int __declspec(dllexport) Hash_Init (Tcl_Interp *Interp)
{
        if (Tcl_InitStubs(Interp, "8.1", 0) == NULL)
                return TCL_ERROR;
        Tcl_CreateObjCommand(Interp, "hash", HashCmd, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
        Tcl_PkgProvide (Interp, "hash", "1.0");
        return TCL_OK;
}

// allow unloading of the DLL
int __declspec(dllexport) Hash_Unload (Tcl_Interp *Interp, int flags)
{
    return TCL_OK;
}

How to compile

I compile the checksum.c to a DLL by using msys and MinGW:

Compile in console C:\msys\msys.bat:

cd "C:/mingw-w64/mingw64/bin"

gcc C:/<yourpath>/checksum.c -shared -o C:/Tcl/lib/checksum/checksum.dll -DUSE_TCL_STUBS -IC:/Tcl/include -LC:/Tcl/lib -ltclstub86 -O3 -march=native