简体   繁体   中英

Return string from function that will be used to create a DLL

I need to create a DLL file that can be used for MS Access and other applications that will return a string when fed parameters. I am fairly familiar with MS Access but an absolute novice at C.

Following is the code I am experimenting with. I want to be able to issue a call like getstring(32.1, 123.2, "here", 25) and have it return a string of up to 60 characters in length. The actual code works fine and buf contains the string I want when it's finished running but I am having trouble handing it back to the calling function.

UPDATE: Ok, I've worked out how to create a DLL and run a function from VBA but I am still struggling to understand how to return strings. I think if I can get this to work, I can work out my whole project. By running the following code I can get VBA to return the square of the input number eg feed it a parameter of 10 and I get an answer of 100

double _stdcall square(double *x)
{
    return *x * *x;
}

However when I run the following code in Excel and feed it a parameter of "test" all I get back is a square box character.

char _stdcall Boxx(char *x)
{
    return *x;
}

In this case all I want it to return is what I entered. If I can get it to return that I hope to be able to replace that with the actual result. Any suggestions?

char * Getstring(double lat, double lon, char *name, double zoom)
{
    char buf[60] = { '\0' };   // Set the max length of the final link string
    int ret = GenShortDroidMapUrl(lat, lon, zoom, name, buf, sizeof(buf) - 1);
    return buf;
}

In the posted code, buf[] is an automatic variable whose lifetime ends after the Getstring() function has returned. Since buf[] will no longer exist when control of the program has returned to the caller, a pointer to this variable will be invalid after Getstring() has returned.

One solution is to pass an additional argument into the Getstring() function to accept the string, along with a size argument. Since buf will decay to a pointer in the function call, the sizeof operator can't be used in Getstring() to find the size of the array, but buf_sz holds this value:

char * Getstring(char *buf, size_t buf_sz, double lat, double lon, char *name, double zoom)
{
    // buf[] has been zero-initialized in the caller
    int ret = GenShortDroidMapUrl(lat, lon, zoom, name, buf, buf_sz - 1);

    return buf;
}

Another option that does not require changing the function signature is to dynamically allocate storage for the returned string. Again, buf is a pointer to char in Getstring() , so the sizeof expression in GenShortDroidMapUrl() will need to be replaced; this time the constant BUF_SZ has been used here. Note that the malloc ed memory will need to be free d by the caller later.

#include <string.h>
#define BUF_SZ  60

/* ... */

char * Getstring(double lat, double lon, char *name, double zoom)
{
    char *buf = malloc(sizeof *buf * BUF_SZ);
    memset(buf, '\0', BUF_SZ);

    /* Or use calloc() and avoid the call to memset() */
    // char *buf = calloc(BUF_SZ, sizeof *buf);

    int ret = GenShortDroidMapUrl(lat, lon, zoom, name, buf, BUF_SZ - 1);

    return buf;
}

If Getstring() is part of a library, you need to ensure that the deallocator function matches the allocation functions. That is, there may be problems if the version of malloc() or calloc() that Getstring() is linked against differs from the version of free() that the calling code is linked against. One solution is to provide a deallocation function with the library. This could be as simple as wrapping free() in another function to be used by the caller to ensure that a matching deallocator is used. Here, the function DLL_Free() is part of the DLL, and malloc() , calloc() , and free() would all be linked against the same library when the DLL is created. The caller that uses Getstring() would use DLL_Free() to deallocate. From the caller, free() may not work as expected to deallocate the memory allocated by Getstring() , but DLL_Free() would since this deallocator uses the version of free() that matches the allocators used in the DLL.

/* Deallocation function included in DLL that matches allocation
 * functions used in library
 */
void DLL_Free(void *ptr)
{
    free(ptr);
}

There are many ways to return a string, but respect the lifetime of buffers:
Can a local variable's memory be accessed outside its scope?

One is to let the caller supply the buffer. Return how much space would have been needed, and a simple comparison will tell you whether it was enough.

Another is to use a static, optionally thread-local, buffer. Beware the restrictions on concurrency and reentrancy.

And finally, you can allocate it dynamically. Remember that it has to be freed with the same system, which on windows often means you have to manually export the way to free it from your DLL. Better not to reinvent the wheel, look at BSTR s for example .

You could either declare buf static and let the function return const char * . But that would not be reentrant . So another solution is to return strdup(buf) , which will return a copy that the caller needs to free after use (otherwise you will have a memory leak).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM