Click here to Skip to main content
15,867,704 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi. I'm trying to export my program as a DLL so initially I had a function that returned a string and worked great. This was the initial function with two underscores appended:

C++
std::string getName()
    {
        char buffer[MAX_COMPUTERNAME_LENGTH + 1];
        DWORD length = sizeof(buffer);
        int i;
    
        bool ok = GetComputerNameExA((COMPUTER_NAME_FORMAT)0, buffer, &length);
        i = strlen(buffer);
        buffer[i] = '_';
        buffer[++i] = '_';
        buffer[++i] = '\0';
        return buffer;
    }


But then I learned I could not export functions which returned a type of
C++
std::string
so I changed to this (in the regular non-DLL program just to get it to work properly):

C++
void GetName(char *nbuf)
    {
        char buffer[MAX_COMPUTERNAME_LENGTH + 1];
        DWORD length = sizeof(buffer);
        int i;
    
        bool ok = GetComputerNameExA((COMPUTER_NAME_FORMAT)0, buffer, &length);
        // if (!ok)
        //     printf("no data bro!\n");
        i = strlen(buffer);
        buffer[i] = '_';
        buffer[++i] = '_';
        buffer[++i] = '\0';
    
        strcpy(nbuf, buffer);
    }

And that works great as all I have to do is allocate memory for
C++
nbuf
and I am good to go. However, when I then try to export this function as a DLL such as this:

C++
extern "C" LIBRARY_API void GetName(char *nbuf)
    {
        char buffer[MAX_COMPUTERNAME_LENGTH + 1];
        DWORD length = sizeof(buffer);
        int i;
    
        bool ok = GetComputerNameExA((COMPUTER_NAME_FORMAT)0, buffer, &length);
        // if (!ok)
        //     printf("no data bro!\n");
        i = strlen(buffer);
        buffer[i] = '_';
        buffer[++i] = '_';
        buffer[++i] = '\0';
    
        strcpy(nbuf, buffer);
    }


I get strange output from areas in memory for
C++
nbuf
Some of the output is text from another class or even a function. So why would it work fine with the regular exe program (always returns the name 1 time as opposed to returning 3 different outputs, 1 of them being the file name but 2 others different output from other sources within my code? All my other functions that I am exporting work perfectly.
C++
LIBRARY_API
is basically a macro defined as such:

C++
#define LIBRARY_API __declspec(dllexport)


Thanks for any help.

What I have tried:

Tried many different variations, with arguments, putting the code inside the other function which behaves differently, etc.
Posted
Updated 15-Apr-22 17:15pm
Comments
Franz Schweizer 14-Apr-22 13:50pm    
it is still doing the same thing. i am getting output such as this:

''$'\001'
jeron1 14-Apr-22 15:54pm    
ANSI vs Unicode issue?
Franz Schweizer 14-Apr-22 14:08pm    
if my program was buggy, why has it been working fine for the last 3 months as a non-DLL program? ive never experienced that until i am trying to use it as an exported function. it is the only function giving me problems.
merano99 14-Apr-22 21:17pm    
The GetComputerNameExA() function works fine in a DLL. Provided that the text fits in the buffer and the terminating 0 is present. The Function strlen can kill your program at this point. I would suggest only write: buffer[length] = 0;

Nope, GetComputerNameExA is not buggy. Your code, on the other hand, is not robust. You should pass a pre-allocated buffer along its size to the GetName and make sure to copy no more than 'size' characters to such a buffer.
 
Share this answer
 
Comments
jeron1 14-Apr-22 13:43pm    
Well said. :thumbsup:
Just because your code was "working fine" for the last 3 months in no way means it was doing things correctly.

CPallini is correct. Your code should expect the caller to pass in a pointer to a pre-allocated buffer and a pointer to the size of that buffer for your function to fill in. Your code should be retrieving the name into an internal buffer and getting the size of it.

Now, it's not just a simple matter of copying the name into the callers buffer. You have to check to see if the callers buffer is big enough to hold the name. If not, don't fill in the buffer, but return the size required of the buffer so the caller via the reference to the size variable passed in, and can allocate a bigger one and retry the call to your code.

If the buffer is big enough, copy the name into the buffer and set the size of the string returned.

Windows follows this very template all the time.
 
Share this answer
 
Comments
CPallini 14-Apr-22 14:42pm    
5.
I tested it quickly and it works without any problems
if you follow the manual page:

https://docs.microsoft.com/de-de/windows/win32/api/sysinfoapi/nf-sysinfoapi-getcomputernameexa

There are several problems with the code above.

1. The buffer size has a fixed size, although the true size is unknown.
What happens if the buffer is not sufficient?
There is actually only one sensible solution here if you do not know the length.
You must first determine the length and then allocate memory appropriately for it.
Here you should remember that the terminating 0 also has space at the end of the string.

The alternative with a pointer to allocated memory and a length like from CPallini and Dave Kreskowiak would
of course also work. But then you would have to double the effort. Once in the DLL and once when called.

2. The first parameter of GetComputerNameExA() should have a value defined in COMPUTER_NAME_FORMAT.

3. I would avoid copying the buffer.

4. There is no harm in providing a return value.

My test program now looks like this:
C++
#define LIBRARY_API __declspec(dllimport)
extern "C" LIBRARY_API BOOL GetName(char **nbuf, DWORD *len);
extern "C" LIBRARY_API BOOL GetName2(char *nbuf, DWORD *len);
#pragma comment( lib, "mydll")

int main()
{
	char *nbuf;
	DWORD len;
	BOOL rtn = GetName( &nbuf, &len);

    if(len>0) {
	  std::cout << "Hostname is: " << nbuf << "\n";
      free(nbuf);
    }
	return 0;
}

Or, when you are sure, that you want it:
C++
int main()
{
	char nbuf[MAX_COMPUTERNAME_LENGTH + 1];
	DWORD len = sizeof(nbuf);
	BOOL rtn = GetName2(nbuf, &len);
	if (rtn != 0) {
		std::cout << "Hostname is: " << nbuf << "\n";
	}
	return 0;
}


The source of dll looks like this
C++
#define LIBRARY_API __declspec(dllexport)

extern "C" LIBRARY_API BOOL GetName(char **nbuf, DWORD *len)
{
	*len = 0;
	DWORD length = 0;
	BOOL  ok = GetComputerNameExA(ComputerNameDnsHostname, NULL, &length);
...

    return ok;
}
 
Share this answer
 
v4
Comments
Shao Voon Wong 15-Apr-22 1:02am    
Got my 5!

It would be best if you provide the full source code for your last snippet, especially on how to allocate memory to the pointer to pointer (nbuf) and call GetComputerNameExA() again.
merano99 15-Apr-22 3:54am    
Thanks! Allocate the memory is simple: *nbuf = (char*)malloc(length + 1);
Well, all I do is simply allocate a buffer and call it from a function that is basically a thread which is called/executed every n minutes.

char *nbuf = new char[MAX_COMPUTERNAME_LENGTH + 1];
if(nbuf == NULL) {
    return;
}
GetName(nbuf);
C++



The truth is, with my other program, only
MAX_COMPUTERNAME_LENGTH + 1
is being defined for the buffer but I am adding 2 underscores so it should be +3 but that did not change anything. I later removed that and added that as part of the time for my second part but that is irrelevant right now. Still, I also am using a GetUserNameA function which works flawlessly.

Merano99, your dll function makes no sense because you are passing off len but never using it at all in the function. It does not do anything besides initialize it to 0. Also the length, according to other sources, shows it should be defined as the size of the pointer, which, on a 64-bit OS, is 8 bytes.

Also why do you have 2 functions. And mention, when I am sure I want it. Want what? Also the 2nd argument of your shows NULL but it is supposed to contain the buffer to where the name is copied to.
 
Share this answer
 
Comments
RedDk 6-May-22 13:21pm    
Using the "Add a Solution" ... button ... is not the same thing as a "Have a Question or Comment" button. What you've done here is seed the wind. Because, unless all these posters have bookmarked this original post of yours, nobody but polyphemus will respond.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900