i am working on making my applications international. After two days digging on msdn i came up with a test, which loads language-specific library containing resources. This is also my first attempt at loading library as a resource, loading strings from it and so on.
Next, according to msdn example at http://msdn.microsoft.com/en-us/library/windows/desktop/dd319071%28v=VS.85%29.aspx, i'm trying the LoadString.
Since string loading for entire application equals a lot of text copying, i thought i would use the - what i think is - memory efficient feature of LoadString, which is setting nBufferMax parameter to zero. According LoadString documentation, it should return a pointer to string resource. I thought i'd make a struct or a class of string pointers and do something along these lines (i extracted only the important bits):
wchar_t textBuf[SOMEVALUE]; // <-- this is how id DOES work
wchar_t *myString; // <-- this is how i would like it
HMODULE resContainer=LoadLibraryEx(L"MUILibENU.dll",NULL, LOAD_LIBRARY_AS_DATAFILE);
if(0!=resContainer){
// this works OK
int copied=LoadStringW(resContainer,IDS_APP_TITLE,textBuf,SOMEVALUE);
// this fails, also gives a warning at compile time about uninitialized variable used.
int copied=LoadStringW(resContainer,IDS_APP_TITLE,myString,0);
}
As you can see i am trying to get myString to become a pointer to loaded resource library's string without actually copying anything.
My question is: am i misunderstanding msdn documentation? Can i or can i not get a pointer to the string directly within loaded library, and simply use it later, e.g. to show a messagebox, without actually copying anything? Until i unload said library?
MSDN says:
[...] If this parameter is 0, then lpBuffer receives a read-only pointer to the resource itself.
It means that a) the pointer must be of type const wchar_t*:
const wchar_t *myString;
and b) you must pass a pointer to the pointer and use an ugly cast:
int copied=LoadStringW(resContainer,IDS_APP_TITLE,(LPWSTR)&myString,0);
Related
There's a function provided by my uni that is supposed to read in a file. In the parameter, there's the fileName parameter. What I don't understand is why they're using a character pointer instead of a simple string?
Also, how would I call this function with a string filename then?
I'm running C++14 on Visual studio 2017 community edition.
double* read_text(char *fileName, int sizeR, int sizeC)
{
double* data = new double[sizeR*sizeC];
int i = 0;
ifstream myfile(fileName);
if (myfile.is_open())
{
while (myfile.good())
{
if (i > sizeR*sizeC - 1) break;
myfile >> *(data + i);
i++;
}
myfile.close();
}
else cout << "Unable to open file";
//cout << i;
return data;
}
Edit: I get it guys, it's stupid. I'll post a separate question then. Thanks for the fast response!
why is this filename parameter a char pointer instead of string?
Because the designer of the API chose to do so. Most people at Stack Overflow are not the author of that API, so we cannot answer this question accurately.
However, there is another similar question that we can answer: What are reasons to use character pointer as a string argument? Let me answer that question instead:
Not using std::string as an argument allows the user of the API to not create a std::string object. This may be useful when:
The API needs to be used in "freestanding" implementations that don't provide the standard library and thus have no std::string. This probably doesn't apply to your particular example since the implementation of the function uses the standard library, but I include this argument for completeness.
The API needs to be used on systems that provide no dynamic memory allocation, which std::string requires.
The dynamic memory allocation that creation of the string may require may be too slow in the context where the API is used (this won't apply to an API that is going to read from disk, but I include the argument here for completeness).
(const) char* makes it possible to use the API from C. This may be relevant because:
The API may have originally been written for C, and has been inherited to a code base that now uses C++, but the API has not been changed in order to maintain backwards compatibility.
Providing a C compatible API allows using the API from other languages that are able to interface with C. Many languages have support for C interfaces while very few languages have support for C++ interfaces.
Also, how would I call this function with a string filename then?
You can get a pointer to a null terminated string using the c_str member function. Unfortunately the API is badly designed and the argument is non-const, while the pointer returned by c_str is const. You can const_cast the constness of the argument away in order to call this function. This is "OK" because the function doesn't actually modify the pointed string.
If you can require C++17 standard and the source string is non-const, then the data member function will be simpler as it doesn't require const_cast. Prior to C++17 there was no non-const overload, so it would require the same const casting, and prior to C++11 the pointed string was not guaranteed to be null terminated.
To make it clear: Using a non-const string argument for this function is bad design - whether that argument is a character pointer to null terminated string, or a reference to std::string.
P.S.There are other, more serious problems:
The caller of the function cannot possibly know how many numbers were read from the file. There is no way of avoiding UB in case the file has less than sizeR*sizeC values.
Returning a bare pointer that owns dynamic memory resource is a very bad design.
The loop that reads from the file checks whether the read was successful after the value has already been added to the array and the value is never overwritten, so the last element written into the array is always has an unspecified value.
I have been able to achieve a program that imports a C++ DLL function and uses it correctly to get the required calculated values. I'm returning the char* values to VB.net using an intptr pointer.
It works fine, however, I cant seem to rest or clear the memory space where the result from the function is stored. When i call the function the first time it gives me the right answers, when it is called the second time, it gives me both the first and the second answers.
Here are relevant parts of my code:
CPM.cpp - The function that calculated the return variables in the cpp file
char* CPMfn(char* sdatabase, int project_num)
{
/* Retrieve data from database and calculate CPM for the selected project number*/
char* testvector = getCPM(sdatabase, project_num);
return testvector;
}
CPM.h - the header file for exporting the function
#pragma once
#ifdef CPM_EXPORTS
#define CPM_API __declspec(dllexport)
#else
#define CPM_API __declspec(dllimport)
#endif
extern "C" CPM_API char* CPMfn(char*, int);
VB.net code to import the DLL, declare the function and use it
'' Import C++ CPM Calculation function from CPM DLL
<DllImport("CPM.dll", CallingConvention:=CallingConvention.Cdecl)>
Private Shared Function CPMfn(ByVal dbstring As Char(), ByVal task As Int32) As System.IntPtr
End Function
'' Get CPM results from DLL function with database location string and selected project number
CPMresults = CPMfn(DBString, Val(Project_IDTextBox.Text))
CPMvalues = Marshal.PtrToStringAnsi(CPMresults)
If CPMvalues.Length() = 0 Then
MsgBox("No tasks for seleccted project")
Else
MsgBox(CPMvalues) ' Show CPM values
End If
As I run it consecutively the string just keeps getting longer i.e. 4th function call would return the values for project 1, 2, 3 and 4.
I've checked online for the past few hours trying to figure out how to return char* from C++ DLLs and then how to clear the intptr.
I just haven't had any luck with the solutions suggested. I would really really appreciate some help.
Thank you!
Per the following MSDN documentation:
Default Marshaling Behavior
The interop marshaler always attempts to free memory allocated by unmanaged code. This behavior complies with COM memory management rules, but differs from the rules that govern native C++.
Confusion can arise if you anticipate native C++ behavior (no memory freeing) when using platform invoke, which automatically frees memory for pointers. For example, calling the following unmanaged method from a C++ DLL does not automatically free any memory.
Unmanaged signature
BSTR MethodOne (BSTR b) {
return b;
}
However, if you define the method as a platform invoke prototype, replace each BSTR type with a String type, and call MethodOne, the common language runtime attempts to free b twice. You can change the marshaling behavior by using IntPtr types rather than String types.
The runtime always uses the CoTaskMemFree method to free memory. If the memory you are working with was not allocated with the CoTaskMemAlloc method, you must use an IntPtr and free the memory manually using the appropriate method. Similarly, you can avoid automatic memory freeing in situations where memory should never be freed, such as when using the GetCommandLine function from Kernel32.dll, which returns a pointer to kernel memory. For details on manually freeing memory, see the Buffers Sample.
So, the DLL needs to dynamically allocate a new char* string each time it returns, and the VB code needs to be told how to free that string properly. There are a few ways to handle this:
have the DLL return a char* (or wchar_t*) string that is allocated with CoTaskMemAlloc(), and then change the PInvoke to take the return value as a string marshaled as an UnmanagedType.LPStr (or UnmanagedType.LPWStr). The .NET runtime will then free the memory for you using CoTaskMemFree().
change the DLL to return a COM BSTR string that is allocated with SysAllocString(), and then change the PInvoke to take the return value as a string marshaled as an UnmanagedType.BStr. The .NET runtime will then free the memory for you using SysFreeString().
if you want to have the DLL return a raw char* (or wchar_t*) string and have PInvoke treat it as an IntPtr (because it is not allocated using CoTaskMemAlloc() to SysAllocString()), then the .NET runtime will have no way of knowing how the string was allocated and so cannot free the memory automatically. So either:
the IntPtr will have to be passed back to the DLL when done being used, since only the DLL will know how the memory was allocated, so only the DLL will be able to free it properly.
have the DLL allocate the char* (or wchar_t*) string using LocalAlloc(), and then the .NET code can use Marshal.PtrToStringAnsi() (or Marshal.PtrToStringUni()) to get a string from the IntPtr, and then pass the IntPtr to Marshal.FreeHGlobal() when done using it.
See the following article for more details (it is written for C#, but you can adapt it for VB.NET):
Returning Strings from a C++ API to C#
Thanks a lot #Remy Lebeau. I've tried implementing the CoTaskMemAlloc() method and it works!. My code is as follows:
In the cpp file i've edited the return value to be allocated using the CoTaskMemAlloc()
char* CPMfn(char* sdatabase, int project_num)
{
/* Retrieve data from database and calculate CPM for the selected project number*/
char* CPMvector = getCPM(sdatabase, project_num);
/* Store results in specially allocated memory space that can easily be deallocated when this DLL is called*/
ULONG ulSize = strlen(CPMvector) + sizeof(char);
char* ReturnValue = NULL;
ReturnValue = (char*)::CoTaskMemAlloc(ulSize);
// Copy the contents of CPMvector
// to the memory pointed to by ReturnValue.
int charlen = strlen(CPMvector);
strcpy_s(ReturnValue, charlen + 1, CPMvector);
// Return
return ReturnValue;
}
In the VB.net file I've written the Dllimport and Marshalling code as follows:
'' Import C++ CPM Calculation function from CPM DLL
<DllImport("CPM.dll", CallingConvention:=CallingConvention.Cdecl, CharSet:=CharSet.Ansi)>
Private Shared Function CPMfn(ByVal dbstring As String, ByVal task As Int32) As <MarshalAs(UnmanagedType.LPStr)> String
End Function
'' Get CPM results from DLL function
Dim teststring As String = CPMfn(cDBString, Val(Project_IDTextBox.Text))
Alternatively I've also tried freeing up the allocated memory manually using the GlobalAlloc() and Marshal.FreeHGlobal() functions but i'm getting the same results (i.e. first call = 1,2,3\n, second call = 1,2,3\n,4,5,6\n instead of just 4,5,6\n).
Here's my code with the GlobalAlloc() method:
In .cpp file
ReturnValue = (char*)::GlobalAlloc(GMEM_FIXED, ulSize);
strcpy_s(ReturnValue, strlen(CPMvector) + 1, CPMvector);
And in VB.net file
<DllImport("CPM.dll", CallingConvention:=CallingConvention.Cdecl)>
Private Shared Function CPMfn(ByVal dbstring As Char(), ByVal task As Int32) As System.IntPtr
End Function
Dim CPMresults As IntPtr = CPMfn(cDBString, Val(Project_IDTextBox.Text))
Dim CPMvalues As String = Marshal.PtrToStringAnsi(CPMresults)
Marshal.FreeHGlobal(CPMresults)
CPMresults = IntPtr.Zero
Thanks for all the help so far!
In C++, does it produce a faster executable if you supply the data to be compared within the brackets of an if statement as the implicit result of a nested function instead of a separate local variable? In the same way, is it more efficient to provide an argument to a function as the result of a nested function called, again instead of a separate local variable?
What I mean is:
int comparison=0;
char *name=nullptr;
GetNameFromRegistry(queried_name); //Unillustrated function that retrieves a name
//entry from the Windows registry, dynamically
//allocates a sufficiently-sized chunk of memory
//to hold it and null-terminates the string.
comparison=strcmp(queried_name,"Fred");
if(comparison==0){
MessageBox(NULL,
"We have found Fred.",
"Name Search",
MB_OK | MB_ICONINFORMATION);
}
as opposed to:
char *queried_name=nullptr;
GetNameFromRegistry(queried_name); //Unillustrated function that retrieves a name
//entry from the Windows registry, dynamically
//allocates sufficiently-sized chunk of memory
//to hold it and null-terminates the string.
if(strcmp(queried_name, "Fred")==0){
MessageBox(NULL,
"We have found Fred.",
"Name Search",
MB_OK | MB_ICONINFORMATION);
}
Another example:
CData gp_data; //CData is a class that holds values, arrays and
//volatile/non-volatilve data for a windows application,
//saving those non-volatile values to the registry to be
//retrieved the next time it is launched.
SendMessage(dialog,
WM_SETICON,
reinterpret_cast<WPARAM>(ICON_SMALL),
reinterpret_cast<LPARAM>(gp_data->Get_Small_Application_Icon()));
as opposed to:
HICON small_icon=0;
CData gp_data; //CData is a class with holds values, arrays and volatile data for
//a windows application, saving non-volatile values to the registry
//to use the next time it is launched.
small_icon=gp_data->Get_Small_Application_Icon();
SendMessage(dialog,
WM_SETICON,
reinterpret_cast<WPARAM>(ICON_SMALL),
reinterpret_cast<LPARAM>(small_icon));
Obviously in the first example, the first form requires an extra local variable be allocated from the stack, but I personally think it is easier to read/debug.
Again, in the second example an extra local variable is required, which once more I think is easier to read. However, perhaps there are performance gains to be had from the first form that compensate for a loss in readability?
I find the second one better. The new variable adds no more semantic to the code. It is just a dummy variable. Its name, comparission, says nothing. Perhaps you could have written:
bool is_specific_name = strcmp(name,"Specific Name") == 0;
if (is_specific_name) {
...
}
At least now the variable tells the reader something. Maybe someone unfamiliar with strcmp would appreciate it. Although, if the audience of your code are people familiar with C, then they'd probably know all about strcmp and they would probably appreciate the shorter code.
However, if we are writing C++, why are we using strcmp and not string comparison? Why use C's char array? Certanly
if (name == "Specific Name") {
...
}
would be the most semantic of all expressions. In that case the extra variable seems quite unecessary.
As for performance, an optimizing compiler should generate the same code for both constructions, given that you don't use the variable anywhere else.
Smart compilers might generate same binary code for both styles. So you can do some compilation and disassembling to confirm it, if you are really intrested.
While passing a character pointer used to reference a string by its address (i.e. directly via its name or &name[0]) the original string must get passed, since we are passing by address.
However, after executing the following code, I got two different values of address for the first element, which, surprisingly, are 2 bytes apart.
Also, modifying the contents of the string in the function, didn't change the content of the array passed, but this is because a new string will have generated a new address, right?
But about the address of the first element being different, how is that possible?
#include<conio.h>
#include<stdio.h>
#include<iostream.h>
void fn(char *arr)
{
cout<<endl<<&arr;
arr="hi";
}
void main()
{
clrscr();
char *arr="hey";
cout<<endl<<"main "<<&arr;//the address is different from that in fn
fn(arr);
cout<<endl<<arr;
}
You are passing a pointer by value, and then comparing the address of the pointer and the copy, which of course differ. If you want to check that they point to the same memory address you can do that:
std::cout << (void*)arr << std::endl;
modifying the contents of the string in the function, didnt change the content of the array passed
You are not modifying the contents of the string, but rather reassigning the copy of the pointer to point to a different string literal. Also note that modifying the pointed memory (the literal) would be undefined behavior.
The only reason that the compiler let the code through (i.e. compiled it) is that there is a backwards compatibility feature that allows you to have a char* that points to the contents of a string a literal (of type const char[]). You should have got a warning and you should avoid doing that.
Just an FYI. I was unable to comment on a similar question about passing character arrays because it was closed as a duplicate, but the issue is fairly important so hopefully you don't mind if i cross-post.
When using strings in a production application you usually go with UTF-8 because it significantly increases the market without a lot of effort.
http://www.joelonsoftware.com/articles/Unicode.html
Most applications also use a string class to encapsulate the characters. Then you can use something like:
void fn(..., const std::string &static_string, ...);
in your header. If you use a library like gettext, your code looks like:
printf(gettext("and suddenly there's one line which is good.."));
where the english strings act as intuitive indices into localization files and you can rapidly and easily switch languages at install or runtime.
If you can't use a class because you're using C then the gettext docs cover this case as well.
My problem is with understanding the finer point of mixed langage programming
and accessing API's in external libraries. My skills at C++ are nonexistent
and at VB, mediocre.
I have a c++ dll compiled (portaudio library), and am trying to access it from VB
(Visual Studio 2005).
I am getting MarshallDirectiveException errors when calling a function, I believe because
I am interacting incorrectly with the dll.
the C++ function and structures are defined as follows:
header info:
typedef int PaHostApiIndex;
...
typedef double PaTime;
...
typedef struct PaDeviceInfo
{
int structVersion; /* this is struct version 2 */
const char *name;
PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/
int maxInputChannels;
int maxOutputChannels;
PaTime defaultLowInputLatency;
PaTime defaultLowOutputLatency;
PaTime defaultHighInputLatency;
PaTime defaultHighOutputLatency;
double defaultSampleRate;
} PaDeviceInfo;
...
const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device );
program usage from docs:
const PaDeviceInfo* Pa_GetDeviceInfo ( PaDeviceIndex device )
Retrieve a pointer to a PaDeviceInfo structure containing information about the specified
device.
Returns:
A pointer to an immutable PaDeviceInfo structure. If the device parameter is out of range
the function returns NULL.
Parameters:
device A valid device index in the range 0 to (Pa_GetDeviceCount()-1)
In the VB program I have:
Private Declare Function Pa_GetDeviceInfo Lib "portaudio_x86.dll" (ByVal dindex As Integer) As PaDeviceInfo
...
Private Structure PaDeviceInfo
Dim structVersion As Integer
<MarshalAs(Runtime.InteropServices.UnmanagedType.LPStr)> Dim name As String
Dim hostapi As Integer
Dim maxInputChannels As Integer
Dim maxOutputChannels As Integer
Dim defaultLowInputLatency As Double
Dim defaultLowOutputLatency As Double
Dim defaultHighInputLatency As Double
Dim defaultHighOutputLatency As Double
Dim defaultSampleRate As Double
End Structure
...
Dim di As New PaDeviceInfo
di = Pa_GetDeviceInfo(outputParameters.device)
This feels wrong as docs state Pa_GetDeviceInfo returns a POINTER to a structure containing info
about the structure, implying function creates the structure initially.
I am completely new to mixed language programming, a c++ utter noob, and a poor VB programmer.
Can anyone guide me in the correct way to attack this problem ?
My feeling is that I need to understand how to get VB to reference a struct in memry created in
the dll, so I need to get vb to understand 'pointer to thing' as a function return.
Much appreciation for any assistance rendered. Please don't just say rtfm, I'm up to my eyes in FM's at
the minute, I just don't know where to look.
Many thanks,
David
Your API function declaration is wrong. The function returns a pointer which is not reflected in your code. The signature translates to VB as follows:
Private Declare Function Pa_GetDeviceInfo Lib "portaudio_x86.dll" ( _
ByVal dindex As Integer _
) As IntPtr
Of course, using an IntPtr directly is not easy. In fact, quite some marshalling is involved:
Dim obj As PaDeviceInfo = _
DirectCast(Marshal.PtrToStructure(ptr, GetType(PaDeviceInfo)), PaDeviceInfo)
(More or less important) side note: since your DLL apparently creates a new object in memory, it also needs to release/destroy it. Be sure to call the appropriate function after using the structure.
Yes, your structure is wrong. You indeed have to get a pointer and then read the memory to which it "points".
I've done external DLL calling in C++ before and it generally involves a huge wading-through of documentation. I don't think anyone here is going to do that for you but I'll try to point you in the proper direction.
First, a pointer is an address, a value which "points" to some location in memory. "dereferencing" a pointer is reading the memory that the pointers to (and if you read or write the wrong memory, the memory can get upset and kill your program).
Further, at a low level, calling a DLL involves copying bits of information to the stack and then having the function retrieve them. The "calling conventions" describe exactly how this is done - there are "c", pascal, and other such conventions.
You will want to call the DLL's function, get a pointer, copy the information pointed-to into your local structure and then continue. The hard thing will be figuring out exactly how to declare the DLL function. If your library documentation has some sample code, that might be where to start.
A short Google does not even show any consistent way to deal with pointers in VB at all. One idea would be to create a short C++ program which would call the DLL and return an object by value. I don't know if this would help but such kludges come up when dealing with external libraries.
Good Luck