Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > How to build a loadable tcl dll with visual studio (microsoft C compiler)?[crosspost in comp.lang.tcl and comp.lang.c++]

Reply
Thread Tools

How to build a loadable tcl dll with visual studio (microsoft C compiler)?[crosspost in comp.lang.tcl and comp.lang.c++]

 
 
Michael Reichenbach
Guest
Posts: n/a
 
      09-19-2007
Example one from http://www.tcl.tk/man/tcl8.4/TclCmd/load.htm:

#include <tcl.h>
#include <stdio.h>
static int fooCmd(ClientData clientData,
Tcl_Interp *interp, int objc, char * CONST objv[]) {
printf("called with %d arguments\n", objc);
return TCL_OK;
}
int Foo_Init(Tcl_Interp *interp) {
if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
return TCL_ERROR;
}
printf("creating foo command");
Tcl_CreateObjCommand(interp, "foo", fooCmd, NULL, NULL);
return TCL_OK;
}

My compile.bat (using the current MinGW gcc port):

set djgpp=c:\MinGW\djgpp.env
set path=%path%;c:\MinGW\bin
gcc -I C:\Tcl\include -s -shared -o a.dll a.cpp C:\Tcl\bin\tcl84.dll
pause

First example doesn`t compile. There is an error.

gcc -I C:\Tcl\include -s -shared -o
a.dll a.cpp C:\Tcl\bin\tcl84.dll
a.cpp: In function `int Foo_Init(Tcl_Interp*)':
a.cpp:13: error: invalid conversion from `int (*)(void*, Tcl_Interp*,
int, char*
const*)' to `int (*)(void*, Tcl_Interp*, int, Tcl_Obj* const*)'
a.cpp:13: error: initializing argument 3 of `Tcl_Command_*
Tcl_CreateObjComman
d(Tcl_Interp*, const char*, int (*)(void*, Tcl_Interp*, int, Tcl_Obj*
const*), v
oid*, void (*)(void*))'

Example two:

#include <windows.h>
#include <tcl.h>

#ifndef DECLSPEC_EXPORT
#define DECLSPEC_EXPORT __declspec(dllexport)
#endif // DECLSPEC_EXPORT

BOOL APIENTRY
DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}

EXTERN_C int DECLSPEC_EXPORT
Tcldemo_Init(Tcl_Interp* interp)
{
#ifdef USE_TCL_STUBS
Tcl_InitStubs(interp, "8.3", 0);
#endif
Tcl_Obj *version = Tcl_SetVar2Ex(interp, "tcldemo_version", NULL,
Tcl_NewDoubleObj(0.1), TCL_LEAVE_ERR_MSG);
if (version == NULL)
return TCL_ERROR;
int r = Tcl_PkgProvide(interp, "Tcldemo", Tcl_GetString(version));

// Call Tcl_CreateObjCommand etc.

return r;
}

EXTERN_C int DECLSPEC_EXPORT
Tcldemo_SafeInit(Tcl_Interp* interp)
{
// We don't need to be specially safe so...
return Tcldemo_Init(interp);
}

This compiled with same compile.bat without any errors or warnings.

I wanted to compile the second example also with visual studio
(microsoft C compiler) and I did add the c:\tcl\include and the
c:\tcl\lib paths. But it doesn`t work, there is an errormessage:

Error 1 error C2664: 'Tcl_CreateObjCommand' : cannot convert parameter 3
from 'int (__cdecl *)(ClientData,Tcl_Interp *,int,char *const [])' to
'Tcl_ObjCmdProc (__cdecl *)'

How can I fix it?

You also don`t need to answer this specific question. Any other example
code which will compile in visual studio and which can be used later as
a loadable tcl module would be much appreciated.
 
Reply With Quote
 
 
 
 
Don Porter
Guest
Posts: n/a
 
      09-20-2007
Michael Reichenbach wrote:
> static int fooCmd(ClientData clientData,
> Tcl_Interp *interp, int objc, char * CONST objv[]) {


With that prototype, your fooCmd routine is a
Tcl_CmdProc. It's a command procedure that takes
string arguments...

> Tcl_CreateObjCommand(interp, "foo", fooCmd, NULL, NULL);


....but you are passing fooCmd to
Tcl_CreateObjCommand() and Tcl_CreateObjCommand
expects a Tcl_ObjCmdProc, and not a Tcl_CmdProc.
The compiler is telling you this error.

Either convert your fooCmd routine to be a
Tcl_ObjCmdProc -- a command procedure that
takes (Tcl_Obj *) arguments -- or call
Tcl_CreateCommand() instead of
Tcl_CreateObjCommand().

DGP
 
Reply With Quote
 
 
 
 
Michael Reichenbach
Guest
Posts: n/a
 
      09-20-2007
Well, I got the example from here:
http://www.tcl.tk/man/tcl8.4/TclCmd/load.htm#M8. 8.4 is the current
stable tcl release and this is the official documentation. Did them use
a used wrong commands inside the official documentation example for years?

I think this problem could compiler based.

Unfortunately what you wrote did not help me.

If you are using in visual studio 7 (2005) or 8 (ocras 200 yourself
and get such an extension running, please post the code here.
 
Reply With Quote
 
Eric Hassold
Guest
Posts: n/a
 
      09-20-2007
Hi,

Michael Reichenbach wrote :
> Well, I got the example from here:
> http://www.tcl.tk/man/tcl8.4/TclCmd/load.htm#M8. 8.4 is the current
> stable tcl release and this is the official documentation. Did them use
> a used wrong commands inside the official documentation example for years?


Definately, documentation is buggy, objv argument should have
declaration "Tcl_Obj *CONST objv[]", not char*. Error is still there in
8.4.16-rc1 doc. This may deserve a quick bug report and fix before
8.4.16 gets out.

>
> I think this problem could compiler based.
>
> Unfortunately what you wrote did not help me.


You only need to fix fooCmd declaration:

static int fooCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[]) {
printf("called with %d arguments\n", objc);
return TCL_OK;
}

and it will compile fine with mingw, cygwin, vs2k5 or any other
compiler. I suggests you also define USE_TCL_STUBS=1
(-DUSE_TCL_STUBS=1), and link with tclstub84.lib instead of tcl84.dll.
This will make your extension more portable across versions and build
environments.

>
> If you are using in visual studio 7 (2005) or 8 (ocras 200 yourself
> and get such an extension running, please post the code here.



Eric
 
Reply With Quote
 
Michael Reichenbach
Guest
Posts: n/a
 
      09-20-2007
I wouldn`t say that I have understood everything. But with some magic,
putting some hints together it`s working now. Was really hard for me as
C++ beginner to get this working, because there was nowhere a working
sample on the web. I have written some step by step instructions, if
someone is interested in solving that problem, see here.

1. File -> new project -> name: Foo -> win32 console application -> dll

2. Tools -> Options -> VC++ Directorys -> Include Files -> added
C:\Tcl\include

3. C++ -> precompiled headers -> Not Using Precompiled Headers

4. Library files -> C:\Tcl\lib

5. Project settings -> Configuration Properties -> Linker -> Input ->
Additional Dependencies -> added c:\tcl\lib\tclstub84.lib

6. use this source (my mistake was to use the #define after #include)
(without the extern "C" it`s also not working, you will get error
message while % load Foo.dll, it says can`t find Foo_Init procedure)

#define USE_TCL_STUBS 1

#include <tcl.h>
#include <stdio.h>

extern "C"
{
__declspec(dllexport) int Foo_Init(Tcl_Interp* interp);
}

static int fooCmd(ClientData clientData, Tcl_Interp *interp, int objc,
Tcl_Obj * CONST objv[]) {
printf("called with %d arguments\n", objc);
return TCL_OK;
}

int Foo_Init(Tcl_Interp *interp) {
if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
return TCL_ERROR;
}
printf("creating foo command");
Tcl_CreateObjCommand(interp, "foo", fooCmd, NULL, NULL);
return TCL_OK;
}

7. Debug -> change to Release

8. Build -> Build solution -> compiles without any errors -> in project
folder under release is File Foo.dll with ~6 kb
 
Reply With Quote
 
grahamaaron grahamaaron is offline
Junior Member
Join Date: Feb 2010
Posts: 1
 
      02-08-2010
Hi,
If you are interfacing TCL and C++ and vice-versa in a multi-threaded windows application, you may find my application of interest….

Thanks to the good work done by Maciej Sobczak in creating his C++/TCL library, I have managed to do wonders with my MFC application and its usage of an TCL interpreter instance. However when I recently tried to build my solution for release, I found my application crashes.

My development goal is to get code written in TCL to utilise an SSH handler that exists as an object in my MFC application. The SSH handler is used to connect to Cisco Devices via a Secure Shell connection to allow my TCL scripts to issue and monitor Cisco CLI (command line interface) commands.

Firstly I will explain what I have going (in debug at least):
1) An MFC C++ application that creates multiple threads (for multiple SSH connections) each with its own interpreter object.
2) To provide TCL access to the other C++ objects within each thread, I created a Function Wrapper DLL that is loaded via a TCL "load" command. This DLL contains a C++ class that is exposed to the world of TCL via the following:
extern "C"
{
__declspec(dllexport) int Main_Init(Tcl_Interp* interp);
}
and the macro :

CPPTCL_MODULE(Main, i)
{
i.class_<TCL_FunctionWrapper>("TCL_FunctionWrapper ")
.def("writeData", &TCL_FunctionWrapper::writeOnly)
.def("readData", &TCL_FunctionWrapper::writeAndRead)
.def("SetSSHConnectionHandler", &TCL_FunctionWrapper::SetSSHConnectionHandler);
}
where writeData, readData and SetSSHConnectionHandler are C++ methods of the class exposed by the DLL.
The SetSSHConnectionHandler takes a string version of the C++ pointer to an object that handles SSH connection as follows:

void TCL_FunctionWrapper::SetSSHConnectionHandler(strin g pHandler)
{
m_pSSHHandler = (CSSH_ConnectionHandler *) (long) atoi(pHandler.c_str());
}

This allows me to inform the DLL which pointer to use to when TCL calls writeData and readData methods.

3) After performing the TCL statement "load C:\functionwrapper.dll Main", (where “Main” is as exposed by the CPPTCL_MODULE(Main, i) ) an instance of the TCL_FunctionWrapper object is created using:
set FW [TCL_FunctionWrapper]

After this point the SetSSHConnectionHandler can be called to initialise the FunctionWrapper with the pointer to the particular thread’s SSH handler (as mentioned above).

As I said above, the whole application/arrangement works perfectly when both the application and the FunctionWrapper DLL are built for debug, but when the I build for release, the
“load C:\functionwrapper.dll Main” causes the application to exit. I can see from my VS 2008 IDE output window that the load is performed but it is soon followed by the application thread and application exiting:
'MyApplication.exe': Loaded 'C:\FunctionWrapper.dll', Symbols loaded.
The program '[3672] MyApplication.exe: Native' has exited with code 0 (0x0).

Another interesting point is that if I use a release version of the MFC application and a debug build of the DLL it works perfectly also. It only seems to fail when I build the FunctionWrapper DLL for release.

I have tried stepping through my Release build (which some of you may not realise you can do, but it is possible) and I could see the last statement executed was the
Tcl_Eval(interp_, script.c_str());
which is used to invoke the “load” TCL command.

Any thoughts would be very much appreciated.
Thanks in advance.
Aaron
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: How include a large array? Edward A. Falk C Programming 1 04-04-2013 08:07 PM
Enabling browser back button for GridView Paging and Sorting in Ajax1.1 and 3.5 (using Visual Studio 2005/ Visual studio 2008) anil reddy ASP .Net 0 02-11-2009 04:22 PM
Is Visual Studio Team System and Visual Studio Foundation Server are same?. Thirumalai ASP .Net 0 05-22-2006 08:48 AM
Re: Visual Studio NET Enterprise Architect 2002 and Visual Studio NET 2003 difference xman C++ 0 08-17-2005 04:00 PM
SWsoft Acronis Disk Director Suite 9.0 Build 508, Acronis OS Selector 8.0 Build 917, Acronis Partition Expert 2003 Build 292, Acronis Power Utilities 2004 Build 502, F-SECURE.ANTI vIRUS.PROXY v1.10.17.WINALL, F-SECURE.ANTI vIRUS v5.50.10260 for CITRI vvcd Computer Support 0 09-25-2004 01:38 AM



Advertisments