undeclared function RegGetValue MinGW C compiler - c

I am trying to compile a C program using MinGW on Windows 7 (64-bit). The code is given below:
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <inttypes.h>
void readRegDwordValue() {
HKEY hKey = HKEY_LOCAL_MACHINE;
char const *subKey = "Software\\Metpl\\My Program";
char const *pValue = "MJP_XXX";
uint32_t flags = RRF_RT_REG_DWORD;
int *pvData = NULL;
int64_t result = RegGetValue(hKey, &subKey, pValue, flags, NULL, pvData, sizeof(DWORD));
if (result != ERROR_SUCCESS) {
printf("Error getting value. Code: ");
printf("%" PRId64 "\n", result);
} else {
printf("Value data: ");
printf("%" PRId32 "\n", *(int32_t*)pvData);
}
}
int main() {
readRegDwordValue();
return 0;
}
I get the following warning:
gcc -O3 -Wall -c -o readReg.o readReg.c
readReg.c: In function 'readRegDwordValue':
readReg.c:13:22: warning: implicit declaration of function 'RegGetValue'; did you mean 'RegSetValue'? [-Wimplicit-function-declaration]
13 | int64_t result = RegGetValue(hKey, &subKey, pValue, flags, NULL, pvData, sizeof(DWORD));
| ^~~~~~~~~~~
| RegSetValue
I have included windows.h which includes winreg.h that contains the definition of the RegGetvalue function. Why is the compiler not able to find it? Also, since it is suggesting that I meant RegSetValue, does it mean it is able to find this one? !!
The linker gives the following error:
gcc readReg.o -o readReg.exe -L -liphlpapi -ladvapi32
d:/__sdk/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: readReg.o:readReg.c:(.text+0x45):
undefined reference to `RegGetValue'
collect2.exe: error: ld returned 1 exit status
What am I missing here? I have been pulling my hair over this for over 8 hours now and not able to understand where I am making the mistake. I have not been able to find much relevant discussion online on this either.
Desperately request some input on this so that I can move forward. Thanks in advance.

Finally! All the hair-pulling bore fruit. And, all the peripheral learning along the journey now seems exhilarating. Following is what works with MinGW-w64 (32-bit):
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <inttypes.h>
char buffer[1024]; // Based on need. This is the max that I need.
DWORD bufferSize = sizeof(buffer);
DWORD readRegDwordValue(HKEY hKey, char const *subKey, char const *pValue) {
long unsigned int *p = NULL;
int64_t result = RegGetValue(hKey, subKey, pValue, RRF_RT_REG_DWORD, p, &buffer, &bufferSize);
if (result != ERROR_SUCCESS) {
return 4294967295; // max unsigned int.
}
return ((DWORD *)buffer)[0]; // return the first element of the buffer.
}
char * readStringValue(HKEY hKey, char const *subKey, char const *pValue) {
long unsigned int *p = NULL;
int64_t result = RegGetValue(hKey, subKey, pValue, RRF_RT_REG_SZ, p, &buffer, &bufferSize);
if (result != ERROR_SUCCESS) {
return "Error";
}
return (char *)buffer;
}
int main() {
char *string = readStringValue(HKEY_LOCAL_MACHINE, "Software\\Metpl\\My Program", "companyName");
printf("string:%s%s%d%s \n", string, " (length = ", strlen(string), ")");
DWORD integerValue = readRegDwordValue(HKEY_LOCAL_MACHINE, "Software\\Metpl\\My Program", "sampleInteger");
printf("integer:(%lu%s\n", integerValue, ")");
return 0;
}
I have tested this code and it gives correct results. Since I only need to get the correct result or an error, I have not added additional error-checking in the code.
Thanks, #CGio3, for pointing me to MinGW-w64. I have made many Portable C programs and a few Windows programs with the version I have and got too comfortable with it, I guess. Anyway, lesson learnt.
Hope this helps someone who has been struggling with the subject.

Related

Including stdlib.h causes code to be unable to be compiled properly

I have a piece of code when I need to include stdlib.h. When I do not include this header, I have no problems compiling my code, but the moment I include the header, my code refuses to compile. It tells me that it expected an identifier or "(" before numerical constant. I have looked through my code and cannot find any issue, and as stated, the code compiles perfectly without including that header.
I am new to C, so excuse my poor code, I am simply wanting to figure out why it would be giving me this error.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int execute(char **args)
{
}
char** parse(void)
{
char command[256];
fgets(command, sizeof(command), stdin);
char delimiter[] = " ";
char * pointer = strtok(command, delimiter);
int tokens = 0;
char ** final_command;
while (pointer != NULL)
{
// final_command = (char**)realloc(final_command,
// (tokens+1)*sizeof(char*));
//printf("%s\n", pointer);
//pointer = strtok(NULL, delimiter);
}
}
int main(int argc, char **argv)
{
int EXIT_SUCCESS = 1;
do
{
printf("MyShell> ");
char ** command = parse();
} while (EXIT_SUCCESS);
return EXIT_SUCCESS;
}
I compile using the command gcc -o MyShell MyShell.c
The exact error I am getting says "error: expected identifier or '(' before numeric constant int EXIT_SUCCESS = 1;"
EXIT_SUCCESS is a standard macro (definition) in C. Do not use it as a variable name.
Like NULL, EXIT_SUCCESS is a macro defined in <stdlib.h>, if you include <stdlib.h> you must not use this identifier for other purposes.
In any case your code does not make much sense because it looks like you've got an infinite loop there in main.

Why using crypt in glibc cause compiler warning?

I tried to compiler the following code(minimum example, see the edit for the whole code):
// a.c
#include <stdio.h>
#define _XOPEN_SOURCE
#include <unistd.h>
int main(int argc, char* argv[])
{
puts((const char*) crypt("AAAA", "$6$2222"));
return 0;
}
Using clang-7 -lcrypt a.c and it emitted the following warning:
minimum.c:8:24: warning: implicit declaration of function 'crypt' is invalid in C99 [-Wimplicit-function-declaration]
puts((const char*) crypt("AAAA", "$6$2222"));
^
minimum.c:8:10: warning: cast to 'const char *' from smaller integer type 'int' [-Wint-to-pointer-cast]
puts((const char*) crypt("AAAA", "$6$2222"));
^
2 warnings generated.
But ./a.out did seem to work:
$6$2222$6GKY4KPtBqD9jAhwxIZGDqEShaBaw.pkyJxjvSlKmtygDXKQ2Q62CPY98MPIZbz2h6iMCgLTVEYplzp.naYLz1
I found out that if I remove #include <stdio.h> and puts like this:
// new_a.c
#define _XOPEN_SOURCE
#include <unistd.h>
int main(int argc, char* argv[])
{
crypt("AAAA", "$6$2222");
return 0;
}
Then there is no warnings.
How to fix these warnings without removing #include <stdio.h>?
Edit:
Whole program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _X_OPEN_SOURCE
#include <unistd.h>
#include <assert.h>
void* Calloc(size_t cnt, size_t size)
{
void *ret = calloc(cnt, size);
assert(ret);
return ret;
}
size_t GetSaltLen(const char *salt)
{
size_t salt_len = strlen(salt);
assert(salt_len > 0);
assert(salt_len <= 16);
return salt_len;
}
char* GetSaltAndVersion(const char version, const char *salt)
{
size_t saltlen = GetSaltLen(salt);
/*
* The format of salt:
* $one_digit_number$up_to_16_character\0
* For more info, check man crypt.
*/
char *ret = (char*) Calloc(1 + 1 + 1 + saltlen + 1, sizeof(char));
char *beg = ret;
*beg++ = '$';
*beg++ = version;
*beg++ = '$';
memcpy((void*) beg, (const void*) salt, saltlen + 1);
return ret;
}
void crypt_and_print(const char *passwd, const char *salt_and_version)
{
char *result = crypt(passwd, salt_and_version);
assert(puts(result) != EOF);
}
int main(int argc, char* argv[])
{
if (argc != 4) {
fprintf(stderr, "argc = %d\n", argc);
return 1;
}
char *salt_and_version = GetSaltAndVersion(argv[2][0], argv[3]);
crypt_and_print(argv[1], salt_and_version);
free(salt_and_version);
return 0;
}
I have tried as #Andrey Akhmetov suggested and put the #define onto the first line, but the warnings did not disappear.
The macro _XOPEN_SOURCE is documented in feature_test_macros(7). In particular, the manpage states:
NOTE: In order to be effective, a feature test macro must be defined before including any header files. This can be done either in the compilation command (cc -DMACRO=value) or by defining the macro within the source code before including any headers.
When you include stdio.h, you indirectly include features.h, which uses the feature test macros as defined at that point. In particular, since _XOPEN_SOURCE and friends aren't defined at that point, crypt.h does not declare crypt.
By the time you define _XOPEN_SOURCE it is too late, since features.h has an include guard preventing it from being included twice.
By swapping the order of the first two lines, the code works without raising this warning on my system:
#define _XOPEN_SOURCE
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
puts((const char*) crypt("AAAA", "$6$2222"));
return 0;
}
Your larger example does not work for a second reason: You wrote _X_OPEN_SOURCE as the name of the macro, while the correct name is _XOPEN_SOURCE.

Segmentation Fault (core dump) with Files (C- linux)

I'm getting a segmentation error (core dump) when I try to run this. It compiles perfectly but I get the error, and I don't know why. There must be a problem with a file writing because without this works good. Any help would be great. Thanks!
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <crypt.h>
#include <string.h>
int
main(void)
{
FILE *f=fopen("shadow1.txt","w");
if (f=NULL)
{
printf("ERROR");
}
unsigned long seed[2];
char salt[] = "$1$........";
const char *const seedchars =
"./0123456789ABCDEFGHIJKLMNOPQRST"
"UVWXYZabcdefghijklmnopqrstuvwxyz";
char *password;
int i;
/* Generate a (not very) random seed.
You should do it better than this... */
seed[0] = time(NULL);
seed[1] = getpid() ^ (seed[0] >> 14 & 0x30000);
/* Turn it into printable characters from ‘seedchars’. */
for (i = 0; i < 8; i++)
salt[3+i] = seedchars[(seed[i/5] >> (i%5)*6) & 0x3f];
/* Read in the user’s password and encrypt it. */
password = crypt(getpass("Password:"), salt);
/* Print the results. */
//fprintf(f,"%s $ %s",password);
printf("Success Registration to file !");
fclose(f);
return 0;
}
if (f=NULL)
{
printf("ERROR");
}
was the problem...
void Register(char u,char p) {
you probably want these to be char * because of the fprintf that treats them as strings:
fprintf(f,"%s $ %s",u,p);
and since you pass char *s in:
char *password,*username;
//...
Register(username,password);
This would most likely have been caught by compiler warnings. It is a lot faster to get your answer from the compiler than from here.
If you can't figure out why your program isn't working, you can enable all the warnings you should need with -Wall -Wextra and turn warnings into errors with -Werror.
You are not allocating space to hold username so it will segfault on the scanf.

Why my C function works well, but got something wrong in PHP-Extension?

I need to call a .so shared library in PHP, so I write C code using "dlopen" and "dlsym" to do this, and it works.
sample.h:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
typedef int (*libfunc) (char *msg, int msglen);
int
sfunc(char *msg, int msglen);
sample.c:
#include "sample.h"
int
sfunc(char *msg, int msglen)
{
void *lib;
libfunc lib_func;
int result;
...
lib = dlopen(THE_LIB_PATH, RTLD_NOW);
lib_func = (libfunc) dlsym(lib, THE_LIB_FUNC);
...
result = lib_func(msg, msglen); // return 0 if success
...
dlclose(lib);
return result;
}
It always return 0.
And then I write a PHP extension as a wrapper, it takes PHP arguments and calls the C code before.
php_sample.c:
...
#include "sample.h"
...
PHP_FUNCTION(s_func)
{
char *msg;
long msglen;
int result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &msg, &msglen) == FAILURE) {
RETURN_NULL();
}
result = sfunc(msg, (int) msglen);
RETURN_LONG(result);
}
Then I added the extension(compiled to .so) to PHP and test the PHP function:
php -r "echo s_func("somestring");"
The call always failed, just return something not zero.
Why? Is there any difference?
Note: I tested this on one other computer and it works. So is there any problems about environments or something?

C program won't compile without warnings when GCC is called by makefile - Works otherwise

So I have a program here, that works perfectly when called with
$ gcc test.c -o test -std=c99
But when called in a makefile:
all: test
test: test.c
gcc test.c -o test -std=c99
it produces some warnings instead and gives a segmentation fault.
terminal output:
gcc -g test.c -o tester -std=c99
test.c: In function ‘test_split’:
test.c:43:2: warning: implicit declaration of function‘strdup[-Wimplicit-function-declaration]
char *str_cpy = strdup(str); // Allow mutation of original string
test.c:43:18: warning: initialization makes pointer from integer without a cast [enabled by default]
char *str_cpy = strdup(str); // Allow mutation of original string
Above error does not appear otherwise and does not produse a segmentation fault.
The code segment that fails is here. string.h is included in header.
The file is just a large file to test other functions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#define CNRM "\x1b[0m"
#define CRED "\x1b[31m"
#define CGRN "\x1b[32m"
int stringsum(char *s);
void stringsum2(char *s, int *res);
int distance_between(char *s, char c);
char *string_between(char *s, char c);
char **split(char *s);
static int test_num = 1;
static void logger(int passed, char *s)
{
char *res;
char *color;
if (passed) {
res = "PASS";
color = CGRN;
} else {
res = "FAIL";
color = CRED;
}
printf("[Test %d][%s%s%s] %s\n", test_num++, color, res, CNRM, s);
}
static void test_split(char *str, char **correct)
{
int i, pass = 1;
char buf[512] = { 0 };
char *str_cpy = strdup(str); // Allow mutation of original string
char **res = split(str_cpy);
if (!res || !res[0]) {
pass = 0;
sprintf(buf, "split() returned NULL or an empty array");
goto end;
}
for (i = 0; correct[i]; i++) {
if (!res[i]) {
pass = 0;
sprintf(buf, "split() returned fewer words than expected");
goto end;
}
}
if (res[i]) {
pass = 0;
sprintf(buf, "split() returned more words than expected");
goto end;
}
sprintf(buf, "\n%-16s%-16s\n", "Returned", "Expected");
for (i = 0; res[i]; i++) {
char tmp[256] = { 0 };
sprintf(tmp, "%-16s%-16s\n", res[i], correct[i]);
strcat(buf, tmp);
if (strcmp(res[i], correct[i])) {
pass = 0;
goto end;
}
}
end:
logger(pass, buf);
free(str_cpy);
}
static void test_stringsum(char *input, int expected)
{
int test;
char buf[256] = { 0 };
test = stringsum(input);
sprintf(buf, "Returned: %d, Expected: %d", test, expected);
logger(test == expected, buf);
}
static void test_distance_between(char *str, char c, int expected)
{
int test;
char buf[256] = { 0 };
test = distance_between(str, c);
sprintf(buf, "Returned: %d, Expected: %d", test, expected);
logger(test == expected, buf);
}
static void test_string_between(char *str, char c, const char *expected)
{
char *res_char;
char buf[256] = { 0 };
res_char = string_between(str, c);
snprintf(buf, sizeof(buf), "Returned: %s, Expected: %s", res_char, expected);
if (!res_char && expected) {
logger(0, buf);
} else {
if (!expected)
logger(!res_char, buf);
else
logger(!strcmp(res_char, expected), buf);
free(res_char);
}
}
static void test_stringsum2(char *input, int expected)
{
int res_int;
char buf[256] = { 0 };
stringsum2(input, &res_int);
sprintf(buf, "Returned: %d, Expected: %d", res_int, expected);
logger(res_int == expected, buf);
}
int main(void)
{
printf("Testing stringsum()\n");
test_stringsum("abcd", 10);
test_stringsum("a!", -1);
test_stringsum("aAzZ", 54);
test_stringsum("ababcDcabcddAbcDaBcabcABCddabCddabcabcddABCabcDd", 120);
test_stringsum("", 0);
test_num = 1;
printf("\nTesting distance_between()\n");
test_distance_between("a1234a", 'a', 5);
test_distance_between("a1234", 'a', -1);
test_distance_between("123456a12334a123a", 'a', 6);
test_distance_between("", 'a', -1);
test_num = 1;
printf("\nTesting string_between()\n");
test_string_between("a1234a", 'a', "1234");
test_string_between("a1234", 'a', NULL);
test_string_between("A123adette er svaretaasd2qd3asd12", 'a', "dette er sv");
test_string_between("", 'a', NULL);
test_num = 1;
printf("\nTesting stringsum2()\n");
test_stringsum2("abcd", 10);
test_stringsum2("abcd!", -1);
test_stringsum2("bbbdbbbbbdbbdbbbbbddbbbbbdbbdbbbbdbd", 90);
test_stringsum2("", 0);
test_num = 1;
printf("\nTesting split()\n");
test_split("abcd", (char *[]){ "abcd", NULL });
test_split("Hei du", (char *[]){ "Hei", "du", NULL });
test_split("Dette er mange ord", (char *[]){ "Dette", "er", "mange", "ord", NULL });
return 0;
}
Any ideas?
Edit: Added full code.
strdup() is defined a bunch of standards (SVr4, 4.3BSD, POSIX.1-2001), but not the C standard. If you specify -std=c99, gcc by default disables functions defined in these standards. The warning about "implicit declaration" is because C has (annoying) legacy feature of declaring functions implicitly, if you just call them, with certain rules such as return type int, which in this case doesn't match your assignment to char*. These warnings are something you should always fix.
In this case, with -std=c99, it can be fixed by using feature test macros.
The linked manual page tells in which cases the function declaration will be included, so for example this will build it without problems:
gcc test.c -o test -std=c99 -D_POSIX_C_SOURCE=200809L
or with gcc you can use this, which enables pretty much all the features of the libc.
gcc test.c -o test -std=c99 -D_GNU_SOURCE
You could also add the define in the .c file as normal #define before you include the relevant system headers. It may be better to have it at the same place as the -std=c99 though (ie. command line option), because here it kinda goes together with that.
A more extreme solution would be to switch to -std=gnu99. But think carefully about doing that, because then it is easy to accidentally use language features which aren't standard C. And then you will run into much more porting trouble, than just writing a few functions, if you need to port the software to other C compiler which doesn't have GNU extensions.
If you ask gcc for C99 compliant code, it will do as you asked and forget it ever knew about strdup()- This function is not covered by the C99 standard, but is rather POSIX only, so strdup is nowhere in a header file in C99 mode.
As your code doesn't see the prototype for that reason, and doesn't know strdup () will return a pointer but rather assumes an integer, it might do all sorts of havoc when 32-/64- mixed mode code where (sizeof(int) != sizeof(char*)) is generated.
Simple remedy: Don't try to use strdup in c99 mode.
Why you seem to see the bug when compiling using make and not otherwise, is something we cannot deduct from the information you have provided. I guess for some reason you aren't switching gcc into c99 mode when using the command line.

Resources