Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

What is the correct way to initialize Tcl from a C program?

78 views
Skip to first unread message

Helmut Giese

unread,
Jan 12, 2023, 11:57:07 AM1/12/23
to
Hello out there,
I used to build and use DLLs regularly - about 15 to 20 years ago, and
now I am not quite sure how to do it. I create a function 'initTcl'
which is called by 'main' like this
error = initTcl(argv[0]);
practically immediately. It looks like this:
---
int initTcl(char* argv0) {
TclpSetInitialEncodings();
Tcl_FindExecutable(argv0);
ourInterp = Tcl_CreateInterp();
if (Tcl_Init(ourInterp) != TCL_OK) {
return TCL_ERROR;
}
return TCL_OK;
}
---
'argv0' is well the name of my program. It fails in 'FindExecutable'
with the error
'Exception thrown at 0x0000000000000000 in StmtParserExe.exe'

Q: What is wrong in 'initTcl'?
I am on Windows using Visual Studio and a .lib file and a 64 bit DLL
from Ashok.

Any help will be greatly appreciated
Helmut

Dave

unread,
Jan 12, 2023, 12:51:34 PM1/12/23
to
Look at tclAppInit.c in either of the source distributions:
win/tclAppInit.c or unix/tclAppInit.c


--
computerjock AT mail DOT com

Harald Oehlmann

unread,
Jan 12, 2023, 12:55:09 PM1/12/23
to
Hi Helmut,

Your stuff is ok. "TclpSetInitialEncodings();" is your function, right ?

I don't see why it should crash there, sorry.

https://wiki.tcl-lang.org/page/How+to+embed+Tcl+in+C+applications

All ok.
When I made dll embedding, I traced through Tcl_FindExecutable.
So, a debug build may help...

Sorry,
Harald

Ralf Fassel

unread,
Jan 12, 2023, 1:13:34 PM1/12/23
to
* Helmut Giese <hgi...@ratiosoft.com>
| Hello out there,
| I used to build and use DLLs regularly - about 15 to 20 years ago, and
| now I am not quite sure how to do it. I create a function 'initTcl'
| which is called by 'main' like this
| error = initTcl(argv[0]);
| practically immediately. It looks like this:
| ---
| int initTcl(char* argv0) {
| TclpSetInitialEncodings();
| Tcl_FindExecutable(argv0);

The manpage of Tcl_FindExecutable says:

On UNIX platforms this procedure is typically invoked as the very first
thing in the application's main program; it must be passed argv[0] as
its argument.
--<snip-snip>--
On Windows platforms this procedure is typically invoked as the very
first thing in the application's main program as well;


Looking at the function body of Tcl_FindExecutable, we see that it calls
TclpSetInitialEncodings() itself, but only after calling TclInitSubsystems():

tcl8.6.12/generic/tclEncoding.c

void
Tcl_FindExecutable(
const char *argv0) /* The value of the application's argv[0]
* (native). */
{
TclInitSubsystems();
TclpSetInitialEncodings();
TclpFindExecutable(argv0);
}

So just do as the manpage says, get rid of the TclpSetInitialEncodings()
and only call Tcl_FindExecutable(argv0).

HTH
R'

Helmut Giese

unread,
Jan 12, 2023, 4:11:53 PM1/12/23
to
Hallo Ralf,
>
> void
> Tcl_FindExecutable(
> const char *argv0) /* The value of the application's argv[0]
> * (native). */
> {
> TclInitSubsystems();
> TclpSetInitialEncodings();
> TclpFindExecutable(argv0);
> }
>
>So just do as the manpage says, get rid of the TclpSetInitialEncodings()
>and only call Tcl_FindExecutable(argv0).
spot on, that was it. Many thanks to you and to Dave and Harald of
course, too. Now my program crashes well into its main parts - but
that's a different story :(
Best regards
Helmut

Nicolas

unread,
Jan 13, 2023, 12:56:41 AM1/13/23
to
Hi, for what it worth (and maybe it can help) here's mine:

int Tk_AppInit(Tcl_Interp *interp) {
#ifdef WIN32
wchar_t* tmp = NULL;
#else
char* tmp = NULL;
#endif
size_t nFP_Length;
Tcl_DString ds4Argv;

/*
* Initialize packages
*/
if (Tcl_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
if (Tk_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}


/*
this is the place to create the exit handler, I do it like that:
Tcl_CreateExitHandler(dL_exitHandler, x);
where x is a pointer of mine
*/

Tcl_SetSystemEncoding(interp, "utf-8");

/*many other stuff goes here...*/

return TCL_OK;
}

#ifdef WIN32
int wmain(int argc, wchar_t **argv) {
/*
use fflush(NULL) to reset everything in case of crashes
*/
fflush(NULL);
#else
int main (int argc, char* argv[]) {
#endif
int i, noprefs;
for (i = noprefs = 0; i < argc; i++) /* prescan ... */
{
#ifdef WIN32
if (wcscmp(argv[i], L"") && i == 1) {
#else
if (strcmp(argv[i], "") && i == 1) {
#endif
user_prefbuf = user_initloadpreferences_file(argv[i]);
argv[i] = user_prefbuf;
}
else if (i > 0) noprefs = 1;
}

#ifndef __MACOSX_CORE__
TclZipfs_AppHook(&argc, &argv);
#endif
//mainLoop
Tk_Main(argc, argv, Tk_AppInit);

exit(EXIT_SUCCESS);
}

Helmut Giese

unread,
Jan 13, 2023, 1:38:47 PM1/13/23
to
Hello Nicolas,
>#ifdef WIN32
>int wmain(int argc, wchar_t **argv) {
> /*
> use fflush(NULL) to reset everything in case of crashes
> */
> fflush(NULL);
>#else
>int main (int argc, char* argv[]) {
>#endif
<snip>
> //mainLoop
> Tk_Main(argc, argv, Tk_AppInit);
>
> exit(EXIT_SUCCESS);
> }
calling Tcl_Main (or Tk_Main) is good if Tcl is the base of your
program. From the doc (Tcl_Main.html):
---
Tcl_Main can serve as the main program for Tcl-based shell
applications. A “shell application” is a program like tclsh or wish
that supports both interactive interpretation of Tcl and evaluation of
a script ...
---
My program, however, is a C program which occasionally needs to call
Tcl procs, so I needed a different approach - and with Ralf's
suggestion it worked.
Best regards
Helmut
0 new messages