Embedding Tcl in a C program - visual-studio

I am trying to create a simple c++ console app that calls the nagelfar syntax checker on a script. I followed the directions here: http://wiki.tcl.tk/19919 , adding the tclstub85.lib to my input, adding the tcl lib directory to my additional libraries, and adding my header directory as well. Linking fails with:
main.obj : error LNK2001: unresolved external symbol _tclStubsPtr
This is my command line for linking:
/OUT:"C:\Users\######\Documents\Visual Studio 2005\Projects\Nagelfar\Release\Nagelfar.exe"
/NOLOGO /LIBPATH:"C:\Tcl\lib" /MANIFEST
/MANIFESTFILE:"Release\Nagelfar.exe.intermediate.manifest" /DEBUG
/PDB:"c:\users\######\documents\visual studio 2005\projects\nagelfar\release\Nagelfar.pdb"
/OPT:REF /OPT:ICF /LTCG /MACHINE:X86 /ERRORREPORT:PROMPT C:\Tcl\lib\tclstub85.lib
kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib
shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
This is the full source code, which I can compile and run fine in Linux using g++:
#include <stdlib.h>
#include <stdio.h>
#include <tcl.h>
#include <string.h>
Tcl_Interp * tcl_interp ;
char fileToCheck[] = "test.tcl";
char dbFile[] = "syntaxdb.tcl";
int main () {
int code, argc;
const char **argv;
char command[1024];
char *results = NULL;
tcl_interp = Tcl_CreateInterp();
Tcl_SetVar2(tcl_interp, "::Nagelfar", "embedded", "1", 0);
code = Tcl_EvalFile(tcl_interp, "nagelfar.tcl");
Tcl_LinkVar(tcl_interp, "::Nagelfar(chkResult)", (char *)&results, TCL_LINK_STRING);
sprintf(command, "synCheck %s %s", fileToCheck, dbFile);
code = Tcl_Eval(tcl_interp, command);
printf("Raw Result: \r\n %s\r\n", results);
code = Tcl_SplitList(tcl_interp, results, &argc, &argv);
{
int i;
for (i = 0; i < argc; ++i)
{
printf("%d/%d: %s\r\n", i+1, argc, argv[i]);
}
}
Tcl_Free(results);
return 0;
}
Solved my own problem: I had x64 ActiveTcl but was linking a 32 bit project. Using the x86 ActiveTcl distribution fixed my issues.

Your error message tells us that you are expecting a stub table (Tcl's goes by the name tclStubPtr once all the macros are expanded), which in turn says that defining the preprocessor symbol USE_TCL_STUBS. That symbol is for use in the case where you are writing a library that is providing extra functionality to Tcl. However, in the case where you are writing a main application that calls functions in the Tcl library — such as “run this code” — you can't (easily) use the stubs mechanism as you'd be needing the stub table before Tcl is in a position to be able to provide it to you.
The fix is to not define USE_TCL_STUBS and to link against the main Tcl library (probably C:\Tcl\lib\tcl85.dll on your system) instead of tclstub85.lib. (I don't know enough about setting up Visual Studio to say what the details of that configuration are.)
You should also add this line to your code before the call to Tcl_CreateInterp():
Tcl_FindExecutable(NULL);
That call is used to allow the Tcl library core to initialize itself, doing little things like getting the memory manager and filesystem interface layer working.

Solved my own problem: I had x64 ActiveTcl but was linking a 32 bit project. Using the x86 ActiveTcl distribution fixed my issues.

Related

Link Error when Compile c program without kernel32.lib

I'm want to Create App that just use ntdll and use security check for it. but when I remove kernel32.lib or uncheck "inherit from parent or project defaults" I get link errors when I build my project.
Link Errors
#include <Windows.h>
#include <processthreadsapi.h>
#include <vcruntime.h>
ULONG WINAPI NtGetCurrentProcessorNumber(void);
void main()
{
int a = 2;
int b = 5;
int sum = a + b;
int Number = NtGetCurrentProcessorNumber();
while (1)
{
}
}
void NtProcessStartup(PVOID DriverObject, PVOID RegistryPath)
{
__security_init_cookie();
//__security_check_cookie();
main();
}
this is a Native Project and work fine when I Remove "Security check" Switch in compiler settings and remove "__security_init_cookie" Function. this project linked to ntdll.lib
Can anyone help me?
When you use security checks __security_xx functions are linked to your module. The linker errors are saying that gs_support.obj (where __security_xx functions reside), requires QueryPerformanceCounter and
other listed functions. QueryPerformanceCounter resides in kernel32, so you need to link with it when using security checks.

Sharing static library between .dll(runtime loading) and .exe

I have a .lib library which provides APIs which have global variables like file/device handles, these APIs are going to be used by the application(.exe) by linking with .lib statically. The application does some initialization using APIs provided by .lib (like opening device/file etc) and loads the .dll during run time to perform writes and reads to the device/file using APIs provided by .lib. The problem is when I link the static library with both .exe and .dll they have different copies of libraries and the initialization done by the application is not retained when .dll is opened during run-time (since .dll and .exe seem to be working with their own copy of .lib). This problem is solved when I make .dll instead of static library and export all APIs and import them in .exe and .dll.
But I want to make the .exe standalone without any .dll dependencies except for run-time .dll .
Here is sample code for scenario
main.c (.exe)
#include <stdio.h>
#include <windows.h>
#include "static_lib.h"
typedef void (*FNPTR)(void);
FNPTR functionname;
int main(){
HINSTANCE hLib;
LPTSTR dllname = "dynamic.dll";
hLib=LoadLibrary(dllname);
if(hLib==NULL)
{
printf("Unable to load dll %s\n", dllname);
return 0;
}
functionname=(FNPTR)GetProcAddress((HMODULE)hLib, (LPCSTR)"dyn_main");
if((functionname==NULL))
{
printf("unable to load test function %s\n", dllname);
FreeLibrary((HMODULE)hLib);
return 0;
}
printf("Var in main: ");
test_func();
printf("calling dyn_main:");
functionname();
printf("back to main:");
printvar();
FreeLibrary((HMODULE)hLib);
return 1;
}
static_lib.c (static library)
#include <stdio.h>
#include <windows.h>
#include "static_lib.h"
int var; //can be file or device handle
int test_func(){ //initializes the device
change_var();
printvar();
return 1;
}
void printvar(void){ //write/read device/file
printf("%d\n",var);
return;
}
void change_var(void){ //opens device/file
var = 1;
return;
}
static_lib.h
#ifndef _STATIC_LIB_H_
#define _STATIC_LIB_H_
#if defined (DLL_EXPORT)
#define DLL_IMPORT_EXPORT __declspec(dllexport)
#else
#define DLL_IMPORT_EXPORT __declspec(dllimport)
#endif
DLL_IMPORT_EXPORT void change_var(void);
DLL_IMPORT_EXPORT void printvar(void);
DLL_IMPORT_EXPORT int test_func();
#endif
dynamic.c (.dll)
#include <stdio.h>
#include <windows.h>
#include "static_lib.h"
__declspec(dllexport) void dyn_main(void){
printvar(); //uses the device
return;
}
The command line for compiling with dynamic linking is
cl /c /nologo main.c dynamic.c
cl /c /nologo /DDLL_EXPORT static_lib.c
LINK /nologo /DLL static_lib.obj
LINK /nologo /DLL dynamic.obj static_lib.lib
LINK /nologo main.obj static_lib.lib
The output is:
main.exe
Var in main: 1
calling dyn_main:1
back to main:1
But when I make a static library and link with .exe and .dll
cl /c /nologo main.c dynamic.c static_lib.c
LIB static_lib.obj
LINK /nologo /DLL dynamic.obj static_lib.lib
LINK /nologo main.obj static_lib.lib
The output is
main.exe
Var in main: 1
calling dyn_main:0
back to main:1
And in real scenario the program crashes as it is invalid device/file handle inside .dll.
Is there anyway to export APIs into .dll from .exe without linker giving unresolved symbol error and maintaining only one copy of static library used by .dll and .exe?
I have searched for the problem and I found this: Dynamic Loading of my DLL with Static Lib in Windows Environment
It says we cannot do this in windows environment. But I want to make sure before thinking of other alternatives.

Steps to make a loadable DLL of some tcl methods in Visual Studio

I want to create a loadable DLL of some of my tcl methods. But I am not getting how to do this. For that I have taken a simple example of tcl api which adds two numbers and prints the sum. Now I want to create a loadable DLL for this to export this tcl functionality.
But I am not understanding how to do it in Visual Studio. I have written a C code which can call this tcl api and get the sum of two integers, but again I don't want it to do this way. I want to create a DLL file to use this tcl functionality. How can I create this DLL on Visual Studio 2010.
Below is my sample tcl program that I am using:
#!/usr/bin/env tclsh8.5
proc add_two_nos { } {
set a 10
set b 20
set c [expr { $a + $b } ]
puts " c is $c ......."
}
And here is the C code which can use this tcl functionality :
#include <tcl.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
Tcl_Interp *interp;
int code;
char *result;
Tcl_FindExecutable(argv[0]);
interp = Tcl_CreateInterp();
code = Tcl_Eval(interp, "source myscript.tcl; add_two_nos");
/* Retrieve the result... */
result = Tcl_GetString(Tcl_GetObjResult(interp));
/* Check for error! If an error, message is result. */
if (code == TCL_ERROR) {
fprintf(stderr, "ERROR in script: %s\n", result);
exit(1);
}
/* Print (normal) result if non-empty; we'll skip handling encodings for now */
if (strlen(result)) {
printf("%s\n", result);
}
/* Clean up */
Tcl_DeleteInterp(interp);
exit(0);
}
I have successfully compiled this code with the below command
gcc simple_addition_wrapper_new.c -I/usr/include/tcl8.5/ -ltcl8.5 -o simple_addition_op
The above code is working with the expected output.
What steps do I need to take to create a loadable dll for this in Visual Studio 2010?
If you look at the answers to this question: here it gives the basic outline of the process you need to go through. There are links from my answer to some Microsoft MSDN articles on creating DLLs.
To go into this in a little more detail for a C++ dll that has Tcl embedded in it.
The first step is to create a new visual studio project with the correct type, one that is going to build a dll that exports symbols. My example project is called TclEmbeddedInDll and that name appears in code in symbols such as TCLEMBEDDEDINDLL_API that are generated by Visual Studio.
The dllmain.cpp look like this:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
allocInterp() ;
break ;
}
case DLL_THREAD_ATTACH:
break ;
case DLL_THREAD_DETACH:
break ;
case DLL_PROCESS_DETACH:
{
destroyInterp() ;
break;
}
}
return TRUE;
}
The allocInterp() and destroyInterp() functions are defined in the TclEmbeddedInDll.h, the reason for using functions here rather than creating the Tcl_Interp directly is that it keeps the details about Tcl away from the DLL interface. If you create the interp here then you have to include tcl.h and then things get complicated when you try and use the DLL in another program.
The TclEmbeddedInDll.h and .cpp are shown next, the function fnTclEmbeddedInDll() is the one that is exported from the DLL - I'm using C linkage for this rather than C++ as it makes it easier to call the function from other languages IMHO.
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the TCLEMBEDDEDINDLL_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// TCLEMBEDDEDINDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef TCLEMBEDDEDINDLL_EXPORTS
#define TCLEMBEDDEDINDLL_API __declspec(dllexport)
#else
#define TCLEMBEDDEDINDLL_API __declspec(dllimport)
#endif
extern "C" {
TCLEMBEDDEDINDLL_API void fnTclEmbeddedInDll(void);
}
void allocInterp() ;
void destroyInterp() ;
// TclEmbeddedInDll.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
extern "C" {
static Tcl_Interp *interp ;
// This is an example of an exported function.
TCLEMBEDDEDINDLL_API void fnTclEmbeddedInDll(void)
{
int code;
const char *result;
code = Tcl_Eval(interp, "source simple_addition.tcl; add_two_nos");
result = Tcl_GetString(Tcl_GetObjResult(interp));
}
}
void allocInterp()
{
Tcl_FindExecutable(NULL);
interp = Tcl_CreateInterp();
}
void destroyInterp()
{
Tcl_DeleteInterp(interp);
}
The implementation of allocInterp() and destroyInterp() is very naive, no error checking is done.
Finally for the Dll the stdafx.h file ties it all together like this:
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
// TODO: reference additional headers your program requires here
#include <tcl.h>
#include "TclEmbeddedInDll.h"

cegcc: failed linking import library compiled with vc++ (mangling issue)

I have application for Windows Mobile 6. To build it I use cegcc (arm-mingw32ce).
Now I have new device with new SDK and some functions from this SDK must be added to this application.
Here comes SDK.
header.h
#ifndef _HEADER_H_
#define _HEADER_H_
#include <windows.h>
#ifndef _SOME_FLAG_
extern "C"
{
#endif
BOOL foo(DWORD *lpdwParam1, DWORD *lpdwParam2);
#ifndef _SOME_FLAG_
}
#endif
#endif
library.lib (this is probably import library compiled with VC++, there is library.dll on device)
Some output from "dumpbin /all library.lib"
2DA0 ?foo##YAHPAK0#Z
2DA0 __imp_?foo##YAHPAK0#Z
Archive member name at 2DA0: library.dll/
correct header end
Version : 0
Machine : 1C2 (Thumb)
SizeOfData : 0000002B
DLL name : library.dll
Symbol name : ?foo##YAHPAK0#Z (int __cdecl foo(unsigned long *,unsigned long *))
Type : code
Name type : undecorate
Hint : 14
Name : foo
I'm able to use this SDK in VS2k5 (installation of Windows Mobile SDK was needed...) but compiling with cegcc fail.
I was trying to compile and link it as C and Cpp. With and without _SOME_FLAG_ defined (C compilation with this flag set fail on extern "C" of course).
The results are:
undefined reference to `foo'
when C compiled or Cpp compiled with extern "C" and
undefined reference to `foo(unsigned long*, unsigned long*)'
when Cpp compiled without extern "C".
Compile:
gcc -O2 -Wall -Wextra -pedantic -Wno-long-long -g -c -DUNICODE -D_UNICODE -Ic:\inc sample.c
Linking:
gcc -static -mconsole -o sample obj\sample.o -lc:\lib\library.lib -laygshell
When I Cpp compile I'm only changing sample.c to sample.cpp (there is only main with simple foo call).
It look like there is a mangling problem (vc++ vs gcc). I've tried to add __attribute__((dllimport)) and __attribute__((cdecl))
How can I solve this problem? Any ideas?
Problem solved. I've forget about possibility of run-time dynamic linking
#include <windows.h>
#include <winbase.h>
#include <header.h>
HINSTANCE dllinst = NULL;
typedef BOOL (CALLBACK LP_FOO)(DWORD *lpdwParam1, DWORD *lpdwParam2);
static LP_FOO Foo;
dllinst = LoadLibrary("library.dll");
Foo = (LP_FOO) GetProcAddress((HMODULE) dllinst, "foo");
Now I can use Foo same as foo.

Difference between Linux and Windows linker

What is the difference in linking on various operating system?
For example the following code produces a linker error on Windows (compiled both with Vs2010 and gcc), but compiles successfully on Linux (Ubuntu,gcc):
extern int foo
int main() {
foo=1;
}
Gcc command:
gcc -shared filename.cpp
If you are trying to compile it as a windows shared library you need something like (code stolen from Wikipedia!) :-
#include <windows.h>
// DLL entry function (called on load, unload, ...)
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}
// Exported function - adds two numbers
extern "C" __declspec(dllexport) double AddNumbers(double a, double b)
{
return a + b;
}
Windows shared modules (DLLs) require a DllMain entry point (executed the first time the module is loaded) and function names need to be exported via the declspec gobledygook before they can be used by another program.

Resources