To call a Tcl command from C code, you've got a choice between two API function families. One is Tcl_EvalObjv, and the other is Tcl_Eval. Each has a number of variants, but the only variant I'll mention is Tcl_EvalObjEx.
Tcl_EvalObjv
This function invokes a single Tcl command, with no processing of substitutions in arguments (unless the command itself does them, of course). It has this signature:
int Tcl_EvalObjv(Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[],
int flags);
It takes the description of what command to call and what arguments to pass to it as a C array of Tcl value references (in argument objv) where the array is of length objc; Tcl guarantees to not modify the array itself, but might transform the values if it does type conversions. The values must all have a non-zero reference count (and all values start with a zero reference count from their birthing Tcl_NewObj call). The interp is the interpreter context, and flags can usually be zero.
The result is a Tcl exception code; if it is TCL_OK, the result of the call can be retrieved from the interpreter using Tcl_GetObjResult, and if the exception code is TCL_ERROR then there was an error and you should usually pass that on out (perhaps adding to the stack trace with Tcl_AddErrorInfo). Other exception codes are possible; it's usually best to just pass those straight on out without doing any further processing (unless you're making something loop-like, when you should pay attention to TCL_BREAK and TCL_CONTINUE).
Tcl_Eval
This function evaluates a Tcl script, not just a single command, and that includes processing substitutions in arguments. It has this signature:
int Tcl_Eval(Tcl_Interp *interp,
const char *script);
The script is any old C string; Tcl won't modify it, but it will parse, bytecode-compile, and execute it. It's up to you to provide the script in a form that will execute a single command without surprises. The interp argument and the result of the function call are the same as for Tcl_EvalObjv.
If you're interested in using this for running a single command, you're actually better off using Tcl_EvalObjv or…
Tcl_EvalObjEx.
This is like Tcl_Eval except it takes the script as a Tcl value reference (and takes flags too).
int Tcl_EvalObjEx(Tcl_Interp *interp,
Tcl_Obj *objPtr,
int flags);
Again, make sure the objPtr has a non-zero reference count before passing it into this function. (It may adjust the reference count during execution.) Again, interp and the result are as documented for Tcl_EvalObjv, and flags is too.
The advantage of this for calling single commands is that you can call Tcl_NewListObj (or any other list-building function) to make the script value; doing so guarantees that there will be no surprise substitutions. But you could also go directly to invoking the command with Tcl_EvalObjv. But if you want to process anything more complex than a single simple call to a command, this is a good place to start as it has a key advantage that plain Tcl_Eval doesn't: it can make the type of the script passed in via objPtr be one that caches the compiled bytecode, allowing quite a reasonable performance gain in some circumstances.
Note that Tcl_EvalObjv is effectively the API that Tcl calls internally to invoke all user code and perform all I/O. (“Effectively” because things get more complex in Tcl 8.6.)
Within a Tcl_CmdProc, all these functions can be called as usual, no special processing or "handling of the interpreter" is needed. If this doesn't work for you, causing crashes or whatever, the interpreter is not at fault, something else must be wrong with your code.
Tcl_CmdProcexecutions hammering onto one and the same interp, there is something fundamentally wrong. Event handlers as commands map to Tcl events managed by the Tcl event loop. Better watch out forTcl_DoWhenIdle,Tcl_QueueEvent_tkintermodule that runs as a part of a Python installation. The custom command implementation there isTkapp_PythonCmd, regular Tcl calls from Python are made viaTkapp_Call, and the event loop is_tkinter_tkapp_mainloop_impl. The linked.pyfile is Python code that demonstrates the aforementioned crash.