This is my code for a program that creates an environment to run a Java .jar file. I am using the _execl function and am programming on Windows:
#include <stdlib.h>
#include <stdio.h>
#include <process.h>
int setenv(const char *name, const char *value, int overwrite);
int main()
{
setenv("JAVA_HOME2", "path\\to\\java.exe", 1);
char *var, *param, *path;
var = getenv("JAVA_HOME2");
param = ("-jar");
path = ("path\\to\\foo.jar");
intptr_t _execl(var, param, path, NULL);
}
int setenv(const char *name, const char *value, int overwrite)
{
int errcode = 0;
if(!overwrite) {
size_t envsize = 0;
errcode = getenv_s(&envsize, NULL, 0, name);
if(errcode || envsize) return errcode;
}
return _putenv_s(name, value);
}
However, VS Code returns the error: expected ')' before '(' token on line 16, which is intptr_t _execl(var, param, path, NULL);.
Does anyone have any solutions?
You're getting an error here:
intptr_t _execl(var, param, path, NULL);
Because this is not a function call but a declaration of a function.
By putting a type name before the function, you're declaring that _execl is a function whose return value is of that type. The parameters given to the function are then taken as the names of those parameters, and since NULL is not a valid identifier for a parameter you get an error.
If you look at the several other places you call a function such as setenv and getenv you're not putting a type name first. So remove it:
_execl(var, param, path, NULL);
And now you have a function call.
This still won't call the function properly, however. The first argument is the path to the executable, and the remaining arguments are command line arguments to the program, and the first command line argument is the name of the program being run. So you actually want to call it like this:
_execl(var, var, param, path, NULL);
Or this:
_execl(var, "java", param, path, NULL);
Also, there's no need for parenthesis around a string constant when you assign it to something. So this:
param = ("-jar");
path = ("path\\to\\foo.jar");
Can be replaced with:
param = "-jar";
path = "path\\to\\foo.jar";
Or you can get rid of these temporaries entirely and pass the strings directly to _execl:
_execl(var, "java", "-jar", "path\\to\\foo.jar", NULL);
Related
I've been trying to read an ini file with inih lib since a few hours, and I still don't totally understand this code, especially configuration* pconfig = (configuration*)user;, and what are the handler function parameters for ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../ini.h"
typedef struct
{
int version;
const char* name;
const char* email;
} configuration;
static int handler(void* user, const char* section, const char* name,
const char* value)
{
configuration* pconfig = (configuration*)user;
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
if (MATCH("protocol", "version")) {
pconfig->version = atoi(value);
} else if (MATCH("user", "name")) {
pconfig->name = strdup(value);
} else if (MATCH("user", "email")) {
pconfig->email = strdup(value);
} else {
return 0; /* unknown section/name, error */
}
return 1;
}
int main(int argc, char* argv[])
{
configuration config;
if (ini_parse("test.ini", handler, &config) < 0) {
printf("Can't load 'test.ini'\n");
return 1;
}
printf("Config loaded from 'test.ini': version=%d, name=%s, email=%s\n",
config.version, config.name, config.email);
return 0;
}
user is a "generic pointer", or "untyped pointer".
Dereferencing that pointer would give you a value of type void which isn't possible.
Therefore you must cast the pointer to the correct type to be able to use it.
As for the arguments and what they're used for you could read the source.
But with a little knowledge of INI files it should be easy to deduce that the section argument is the name of a section in the file, while name is the current value name, and value is the value itself.
So assuming a section and value like
[foo]
bar = something
Then section would be "foo", name would be "bar" and value would be "something".
And the user argument is very likely the third argument passed to ini_parse.
user is obviously a pointer to configuration instance you gave to ini_parse.
void* is only kind of type erasure for pointers available in C.
section is name of section of .ini file,
name is key name, value is key's value.
ini_parse calls handler for every key, passing it configuration and result of parsing iteration. What handler does with that information, is to be defined by user of library.
Objective: Retrieve the class name of the current foreground window with plain C.
I have the following code to retrieve the class name:
PWSTR win_class = NULL;
GetClassNameW(hwnd,&win_class,MAX_PATH);
if(win_class != NULL)
free(win_class);
I am getting the following warnings:
warning C4047: 'function': 'LPWSTR' differs in levels of indirection
from 'PWSTR *' warning C4024: 'GetClassNameW': different types
for formal and actual parameter 2
I have two questions: How to solve those warnings, and how should I create an if condition to validate the result of the function GetClassName and set the value of win_class to "NOT FOUND" in case that the function does not find the class name?
The GetClassNameW() function does not allocate the memory needed for the returned class name - you have to do that (or simply provide automatic storage).
To check for success, simply test the return value of the function: if it succeeds, that will be the length of the class name string (in characters); if it fails, the value will be zero.
Here's a short, runnable program that gets the class name for the console window:
#include <Windows.h>
#include <stdio.h>
int main()
{
HWND hwnd = GetConsoleWindow();
wchar_t win_class[_MAX_PATH];
int status = GetClassNameW(hwnd, win_class, _MAX_PATH);
if (!status) wcscpy(win_class, L"NOT FOUND");
printf("%ls\n", win_class);
return 0;
}
When calling GetClassNameW(), you are passing a PWSTR* (wchar_t**) where a LPWSTR (wchar_t*) is expected. That is what the compiler is complaining about.
GetClassName() requires you to pre-allocate a character buffer and pass in a pointer to it, along with the buffer size. The function will not allocate a buffer and return a pointer back to you, like you are expecting. It will merely fill in your provided buffer as needed.
Try something more like this:
WCHAR win_class[256] = {0};
int win_class_len = 0;
HWND hwnd = GetForegroundWindow();
if (!hwnd)
{
// error handling as needed...
lstrcpyW(win_class, L"WINDOW NOT FOUND");
win_class_len = lstrlenW(win_class);
}
else
{
win_class_len = GetClassNameW(hwnd, win_class, 256);
if (win_class_len == 0)
{
DWORD err = GetLastError();
// error handling as needed...
lstrcpyW(win_class, L"CLASS NOT FOUND");
win_class_len = lstrlenW(win_class);
}
}
// use win_class as needed, up to win_class_len characters...
TCHAR is the universal char type working for Unicode and ANSI. GetClassName is the corresponding function replaced with GetClassNameA or GetClassNameW. If you need static string use TEXT() macro like TCHAR * s = TEXT("abc");
TCHAR win_class[MAX_PATH];
int res = GetClassName( hwnd, win_class, MAX_PATH );
if ( res > 0 )
// success
Your error is that win_class was unallocated (NULL) string pointer. GetClassName needs valid memory address of buffer.
You need to check if you function succseed. To do so, print the return value of the function.
Failiure will be presented by the value 0.
I’ve been experimenting with the Perl XS C API and have hit a roadblock.
I have simplified my example below. Assuming an existing struct MyObject then to access property “a” or “b” and create a hash for either one I could use the following code:
typedef struct {
const char *prop_a;
const char *prop_b;
struct {
const char **items;
int num;
} names;
} MyObjectInfo;
typedef MyObjectInfo *MyObject;
MODULE = my_obj PACKAGE = MyObject PREFIX = my_obj_
SV *
my_obj_a(o)
MyObject o
CODE:
SV *info = newHV();
hv_store(info, “a”, 1, newSVpvn(o->prop_a, strlen(o->prop_a)), 0);
int i;
for(i = 0; i < o->names.num; i++) {
const char *n = o->names.items[i];
hv_store(info, n, strlen(n), newSViv(i), 0);
}
RETVAL = sv_2mortal(newrv_noinc(val));
OUTPUT:
RETVAL
SV *
my_obj_b(o)
MyObject o
CODE:
SV *info = newHV();
hv_store(info, “b”, 1, newSVpvn(o->prop_b, strlen(o->prop_b)), 0);
int i;
for(i = 0; i < o->names.num; i++) {
const char *n = o->names.items[i];
hv_store(info, n, strlen(n), newSViv(i), 0);
}
RETVAL = sv_2mortal(newrv_noinc(val));
OUTPUT:
RETVAL
What I want to do is share some of the functionality in a utility function like this
SV *create_obj_hash(MyObjectInfo *o, const char *k, const char *p) {
SV *val = newHV();
hv_store(val, k, strlen(k), newSVpvn(p, strlen(p)), 0);
int i;
for(i = 0; i < o->names.num; i++) {
const char *n = o->names.items[i];
hv_store(info, n, strlen(n), newSViv(i), 0);
}
return val;
}
MODULE = my_obj PACKAGE = MyObject PREFIX = my_obj_
SV *
my_obj_a(o)
MyObject o
CODE:
SV *info = create_obj_hash(o, “a”, o->prop_a);
RETVAL = sv_2mortal(newrv_noinc(val));
OUTPUT:
RETVAL
SV *
my_obj_b(o)
MyObject o
CODE:
SV *info = create_obj_hash(o, “b”, o->prop_b);;
RETVAL = sv_2mortal(newrv_noinc(val));
OUTPUT:
RETVAL
But, when I do the macro expansion within create_obj_hash() fails with the following messages.
myobj.xs: In function 'create_obj_hash':
/usr/lib/x86_64-linux-gnu/perl/5.28/CORE/perl.h:175:16: error: 'my_perl' undeclared (first use in this function); did you mean 'my_fork'?
# define aTHX my_perl
^~~~~~~
ppport.h:6145:41: note: in definition of macro 'MUTABLE_PTR'
# define MUTABLE_PTR(p) ({ void *_p = (p); _p; })
^
/usr/lib/x86_64-linux-gnu/perl/5.28/CORE/hv.h:651:17: note: in expansion of macro 'MUTABLE_HV'
#define newHV() MUTABLE_HV(newSV_type(SVt_PVHV))
^~~~~~~~~~
/usr/lib/x86_64-linux-gnu/perl/5.28/CORE/perl.h:188:18: note: in expansion of macro 'aTHX'
# define aTHX_ aTHX,
^~~~
/usr/lib/x86_64-linux-gnu/perl/5.28/CORE/embed.h:532:40: note: in expansion of macro 'aTHX_'
#define newSV_type(a) Perl_newSV_type(aTHX_ a)
^~~~~
/usr/lib/x86_64-linux-gnu/perl/5.28/CORE/hv.h:651:28: note: in expansion of macro 'newSV_type'
#define newHV() MUTABLE_HV(newSV_type(SVt_PVHV))
^~~~~~~~~~
myobj.xs:42:19: note: in expansion of macro 'newHV'
return (void*)newHV();
Thank you very much in advance,
Brian
First of all, you might be missing some or all of the following:
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
The main issue is that you aren't providing the context to the API calls.
Some builds of Perl allow processes to have multiple instances of the interpreter running at once. If -Dmultiplicity was used when Perl was created, the build will support this. (You can check this using perl -V:usemultiplicity.) -Dmultiplicity is implied by -Dusethreads, the option to build a perl with thread support (since an instance of the interpreter is created for each thread).
As such, a large number of Perl API calls require the caller to provide a context ("THX") which identifies the interpreter to use. Think of the interpreter as an object (in the OOP sense of the word), and the context as the invocant.
In XS code, a variable containing the context is automatically created for you. This variable is automatically passed to Perl API call through the use of macros.
#define newSVpvn(a,b) Perl_newSVpvn(aTHX_ a,b)
// ^^^^^
// Causes the context to be passed
// to Perl_newSVpvn, the real name
// of newSVpvn.
As such, you'll need the context to make this work (no matter which of newSVpvn and Perl_newSVpvn you use). To obtain the context, use the following macros:
If your function has no parameters besides the context,
Use pTHX as the first parameter of your function declaration.
Use aTHX as the first argument in calls to your function.
If your function has parameters besides the context,
Use pTHX_ as the first parameter of your function declaration.
Use aTHX_ as the first argument in calls to your function.
"p" stands for "parameter", "a" stands for "argument", and "_" represents a comma.
In your case, you'd use
STATIC SV *create_obj_hash(pTHX_ MyObjectInfo *o, const char *k, const char *p) {
#define create_obj_hash(a,b,c) create_obj_hash(aTHX_ a,b,c)
...
}
Thanks to the #define, you can continue using
SV *info = create_obj_hash(o, "b", o->prop_b);
Untested. Let me know if there are any problems.
I'm working on a network service that based on commands it receives over the network, it has workers perform different jobs. I want to have a log entry for every time a certain worker is tasked with doing some job.
I have a function (say function_caller) which, among other things, calls another function which it receives its pointer as an argument. I'd like to have my logger notify what kind of function function_caller calls.
Originally I wanted the function_caller to receive some enum instead of a function pointer, provide the enum to the logger, and then use a helper function which returns a suitable pointer based on the enum. However, function_caller is already deeply tangled in the codebase I'm working on, and it looks like it would be a lot of work to refactor all the functions that call function_caller to choose the right enum and use a new argument.
So my next idea was having a switch that for every function pointer will have some string representation of, but I've never stumbled upon something like that (and struggled to find anyone even mentioning such an idea on Google), so I have a feeling I might be missing some serious downsides to this option.
The only significant problem I see is that every developer that decides to pass a new kind of function pointer to function_caller will have to somehow know to update the switch, otherwise it will fail.
Am I missing anything else? Or maybe there's some other approach I should consider?
How about something like this? Instead of a switch, store a table of functions and their name strings. The table can even be kept dynamically updated, unlike a switch case. You will not need to walk along the edge of the standard as well!
#include <stdio.h>
typedef void (*callback_t) (void);
void first (void) { printf("%d", 1); };
void second (void) { printf("%d", 2); };
void third (void) { printf("%d", 3); };
typedef struct fntable_t
{
callback_t fn;
char *name;
} fntable_t;
fntable_t fntable[] =
{
{ first, "first" },
{ second, "second" },
{ third, "third" }
};
char* log_str(callback_t c)
{
for(int i = 0; i < sizeof(fntable) / sizeof(fntable_t); i++)
{
if(fntable[i].fn == c)
return fntable[i].name;
}
return "unknown";
}
void function_caller(callback_t c)
{
printf("%s",log_str(c));
c();
}
int main(void)
{
function_caller(first);
function_caller(second);
function_caller(third);
return 0;
}
You could replace function_caller with a wrapper macro of the same name that calls the renamed function function_caller_internal which gets an additional string argument. The wrapper macro can then pass an additional stringified function name.
This works only if function_caller is always called with a function name, not a function pointer variable.
Example:
#include <stdio.h>
static void funcA(void)
{
printf("This is funcA\n");
}
static void funcB(void)
{
printf("This is funcB\n");
}
/* renamed function gets an additional string argument */
static void function_caller_internal(void (*func)(void), const char *name)
{
printf("calling %s\n", name);
func();
}
/* wrapper macro stringifies the function name to pass it the additional argument */
#define function_caller(func) function_caller_internal(func, #func)
int main(void)
{
/* unchanged calls */
function_caller(funcA);
function_caller(funcB);
return 0;
}
This prints
calling funcA
This is funcA
calling funcB
This is funcB
If you can change the API of the functions, then consider using __func__ to get the textual name of each function. If you can have a function pointer type along the lines of this:
typedef void func_t (const char** name);
Then you can have each function return its name to the caller.
void foo (const char** name)
{
/* do foo stuff here */
*name = __func__;
}
void bar (const char** name)
{
/* do bar stuff here */
*name = __func__;
}
Example:
#include <stdio.h>
typedef void func_t (const char** name);
void foo (const char** name)
{
/* do foo stuff here */
*name = __func__;
}
void bar (const char** name)
{
/* do bar stuff here */
*name = __func__;
}
const char* function_caller (func_t* func, const char** name)
{
func(name);
return *name;
}
int main(void)
{
static func_t*const func [] =
{
foo,
bar,
};
const char* name;
for(size_t i=0; i<sizeof func/sizeof *func; i++)
{
puts( function_caller(func[i], &name) );
}
}
Assuming your codebase has sane variable names and function names, you can add a char * argument to your function caller:
void function_caller(char *name, int fpnt());
and then provide a macro:
#define function_caller_autoname(fpnt) function_caller(#fpnt, fpnt)
(Or, for spaghetti code, you can provide a macro with the same name as the function).
The #fpnt will be expanded by the proceprocessor to a string literal with the function name.
Then when your codebase called:
function_caller(some_function)
refactor it to:
function_caller_autoname(some_function)
# will be expanded to by the processor:
# function_caller("some_function", some_function)
or refactor it manually to provide the name/identificator/description of the function:
function_caller("Some function: ", some_function)
That way you can pass a custom string that describes the function along with the pointer. Also, each developer can pass a custom description string.
I would need some help. I been doing it for hours and is not able to get it to work. Generally, I have a function which access a kernel Driver and I would like to pass that function as a parameter to another function that include some pthread code. I researched and found out that I may need a function pointer.
Here is the function which I want to pass as a parameter.
static void kernelTest(char Send[BUFFER_LENGTH])
{
int fd = open("/dev/kernelTest", O_RDWR);
}
Here is the function which I want to pass in:
static void createKThread(void (*f)(char *))
{
pthread_t t1;
int ret;
ret = pthread_create(&t1, NULL, (*f)(char), NULL);
pthread_join(t1, NULL);
}
I attempted the function pointer but it is giving me error.
error: expected expression before ‘char’
I greatly appreciate any help rendered. Thank You!
(*f)(char) is invalid syntax. It looks like you're attempting to call the function f and passing char as a parameter, which you can't do.
Since you're not actually calling f, just pass it to pthread_create directly:
ret = pthread_create(&t1, NULL, f, NULL);
There's still a problem with this, however. The third parameter to pthread_create is expected to be of type void *(*)(void *), i.e. a pointer to a function that has a void * parameter and returns a void *. Your function has type void (*)(char *), so the parameters are incompatible.
You need to either change the signature of kernelTest to match what pthread_create expects:
static void *kernelTest(void *param)
{
char *send = param;
int fd = open("/dev/kernelTest", O_RDWR);
return NULL;
}
Or you need to create a wrapper function which matches pthread_create:
static void *kernelTest_wrapper(void *param)
{
char *send = param;
kernelTest(send);
return NULL;
}