[TR] - This C function is used to create a new command usable from the Tcl script level. The definition is Tcl_Command '''Tcl_CreateObjCommand'''(''interp'', ''cmdName'', ''proc'', ''clientData'', ''deleteProc'') so it returns a Tcl_Command (which is a token for the command) and takes 5 arguments: * ''interp'' - the interpreter in which to create the new command * ''cmdName'' - the name of the new command (possibly in a specific namespace) * ''proc'' - the name of a C function to handle the command execution when called by a script * ''clientData'' - some data associated with the command, when a state needs to be taken care of (a file for example); this is typically used where a ''proc'' is used to create a whole family of commands, such as the instances of a kind of [Tk] widget. * ''deleteProc'' - a C function to call when the command is deleted from the interpreter (used for cleanup of the ''clientData'') which may be NULL if no cleanup is needed. A full example of the usage can be found in: [Hello World as a C extension]. Here is an example from the [sqlite] extension used to create the 'sqlite' command: Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0); Taking the same sqlite example, we can go a step further and look at how to handle clientData. When sqlite opens a database, a new command is created which handles SQL queries on that database file. The command must of course know this file and since you can have more databases open at one point, you don't want to mix them. That is what the clientData parameter can handle, it handles so-called 'state data'. It is best to hold these clientData in a struct (thanks to [schlenk] and [dgp] for hints on this) and that could look like this: typedef struct dbData { Tcl_Obj *fileObj; /* the name of the file */ Tcl_Channel chan; /* the channel to the openend shape file */ } dbData; So if we assume a command named 'mydb' that needs access to these data, we might create the command as follows (this is a fictitious example): dbData *adb; adb = (dbData*)ckalloc(sizeof(*adb)); /* given an already opened channel 'mychan', put the handle into the structure, so the 'mydb' command can access it */ adb->chan = mychan; /* given a filename was given on the command line from script level, we can store it in the structure like this (assuming it came as the first argument): */ adb->fileObj = Tcl_DuplicateObj(objv[1]); Tcl_IncrRefCount(adb->fileObj); Tcl_CreateObjCommand(interp, "mydb", DbObjCmd, dbData, DbDeleteCmd); Note here, that we used a [Tcl_Obj] for the name of the file. This is good style and an overall advantage. We could have used 'char *filename' instead in the structure, but then our memory space would get lost after the completion of the function without adding extra code for memory management ourselves. Using a Tcl_Obj will do everything for us automatically (using reference counts -> see [Tcl_Obj refCount HOWTO]). The only thing we need to do is to increease the reference count on the Tcl_Obj each time a new command is created from the same C function (we might have more than one file open at any time). When the file is closed, we must decrease the count again (thanks to [Pat Thoyts], [MJ], and [RFox] for explaining and helping here). The clientData have now been used to "bind" the created command to the database file for which is was created via a structure holding the state data. The 'mydb' command will now be handled by the DbObjCmd C function and the clientData are "dbData" in this case holding the data for an opened file, so the otherwise generic DbObjCmd function can operate on the right file. You can pass the client data on to the created command as is, there is no need to cast this because Tcl won't cast it to something else and poke around inside (thanks to [DKF] for this clarification). This is how the DbObjCmd function could look like: static int DbObjCmd(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; int objc; Tcl_Obj * CONST objv[]; { dbData *bbb = (dbData*)clientData; /* do something intelligent here ... */ } As you can see, the DbObjCmd not only gets passed our clientData but also some other information, but always matching the type Tcl_ObjCmdProc: typedef int Tcl_ObjCmdProc( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); So this is a template for all those created commands that we might create and use. Since we hold a reference to the state data, we must free this space eventually. This is why we also have defined a DbDeleteCmd above. This command is called before our 'mydb' command is deleted from the interpreter. ... '''To be continued ...''' ---- See also: * more on clientData and their advantages/disadvantages: [static data in command procedures] ---- [Category Tcl Library]