/* * TclGUID.h v1.1 2-26-2005 Scott Nichols * * This software is provided "AS IS", without a warranty of any kind. * You are free to use/modify this code but leave this header intact. * */ /* TCL Function prototype declarations */ #ifndef TclGUID_H #define TclGUID_H #define USE_NON_CONST #define TCL_USE_STUBS #include <tcl.h> #include "StdAfx.h" #include <afxdisp.h> extern "C" { __declspec(dllexport) int Tclguid_Init(Tcl_Interp* interp); } static int GetGUID_ObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int GetDate_ObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); #endifBegin Main Windows DLL Code
/* * TclGUID.cpp, v1.1 2/26/2005, * Authored by Scott J. Nichols * * This software is provided "AS IS", without a warranty of any kind. * You are free to use/modify this code but leave this header intact. */ #include "TclGUID.h" static int GetGUID_ObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { GUID guid; // create random GUID guid = GUID_NULL; ::CoCreateGuid(&guid); if (guid == GUID_NULL) { Tcl_Obj *obj_result = Tcl_NewStringObj((const char *)"Unable to create GUID", -1); Tcl_SetObjResult(interp, obj_result); return TCL_ERROR; } BYTE * str; UuidToString((UUID*)&guid, &str); Tcl_UtfToUpper((char *)str); // Return the GUID to the Tcl Interpreter Tcl_Obj *obj_result = Tcl_NewStringObj((const char *)str, -1); Tcl_SetObjResult(interp, obj_result); RpcStringFree(&str); return TCL_OK; } static int GetDate_ObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { if (objc < 2) { Tcl_WrongNumArgs(interp,1,objv, "value"); return TCL_ERROR; } double f; Tcl_GetDoubleFromObj(interp,objv[1],&f); COleDateTime d = COleDateTime::COleDateTime(f); int M = d.GetMonth(); int D = d.GetDay(); int Y = d.GetYear(); int h = d.GetHour(); int m = d.GetMinute(); int s = d.GetSecond(); char date[20]; sprintf(date,"%i/%i/%i %i:%i:%i",M,D,Y,h,m,s); // Return the date value to the Tcl Interpreter Tcl_Obj *obj_result = Tcl_NewStringObj((const char *)date, -1); Tcl_SetObjResult(interp, obj_result); return TCL_OK; } /* Main Routine in the TCL Extension DLL */ int Tclguid_Init( Tcl_Interp *interp) { #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1 // Does the TCL interpreter support version 8.3 of TCL? if (Tcl_InitStubs(interp,"8.3",0) == NULL) return TCL_ERROR; #endif Tcl_CreateObjCommand(interp, "GetGUID", GetGUID_ObjCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "GetDate", GetDate_ObjCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); return (Tcl_PkgProvide(interp,"TclGUID","1.0") == TCL_ERROR ? TCL_ERROR : TCL_OK); }Begin Sample Tcl Call Code
package require TclGUID clock format [clock scan [GetDate 38409.7202431]]Returns:
Sat Feb 26 5:17:09 PM Central Standard Time 2005
RS has taken this breakfast challenge to do some thinking :) The Unix "era" date is 1 Jan 1970, while OLE/COM's is 30 Dec 1899 - 25569 days earlier. Both seem to take a fixed day length of 86400 seconds, which ignores the problem of leap seconds, but anyway. The following code passes Scott's test:
proc fdate f {expr {round(($f-25569)*86400)}}and in the other direction, Unix time to OLE/COM time:
proc date2fdate time {expr {$time/86400.+25569}}Testing:
% clock format [fdate 38409.7202431] -gmt 1 Sat Feb 26 17:17:09 GMT 2005
snichols RS, your Tcl conversion code works great! Yours is much simpler than having to convert the value from a C/C++ Tcl extension. I'm going to use your Tcl code instead. Thank you.
male - 2007-08-17: I ran into the same problem, where a NC control returns DATE values over its COM interface. And I needed to use them as clock values. The result is ...
% set date 39280.84648148148 % clock format [fdate $date] Tue Jul 17 22:18:56 +0200 2007 % clock format [clock scan now] Fri Aug 17 21:15:58 +0200 2007But ... perhabs the NC control has a wrong adjusted time.