I have am trying to receive information from a EXE that was written in Delphi. The EXE passes me a pointer to one of its data structures:
Type
RecordType = Record
St: WideString;
Next: Pointer;
End;
Var
DataRec: ^RecordType;
So in Visual Studio MFC I have declared a data type that should be similar:
struct RecordRec
{
BSTR St;
void *Next;
};
RecordRec *DataRec;
The Delphi Help says that a WideString is compatible with a BSTR, however, this does not work. When I look at my St in Debug Mode it says
"0x0000000000000000 <Bad Ptr> wchar_t *"
I don't know how to declare the equivalent of a WideString in Visual Studio MFC.
If it was a ShortString I would declare:
struct RecordRec
{
BYTE StLen;
char St[255];
void *Next;
};
but this does not work for a WideString and I really don't think I should declare a variable with ~2^30 (1,073,741,824) characters in it.
What am I missing? I really hope that someone can help.
A Delphi WideString is indeed a wrapper for a BSTR, however, that does not mean a raw BSTR pointer can be passed as-is from one process to another. Its data has to be marshalled when passing across process boundaries. COM normally handles that automatically, but passing a raw BSTR pointer manually does not.
So, if you can't change the Delphi app to provide an IPC-safe data block for the character data (similar to the ShortString workaround), then the receiving app will have to marshal the BSTR data manually. It can use ReadProcessMemory() for that:
read the BSTR's length from within the Delphi app's address space (a BSTR's character data is prefixed with a 4-byte integer specifying its length in wchar_t elements)
allocate a wchar_t[] array of the specified length within its own address space
read the character data from the Delphi app's address space into the array in its own address space.
For example (error handling omitted for brevity):
RecordRec *DataRec = ...;
std::wstring DataSt;
if (DataRec->St)
{
HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, TheDelphiAppProcessID);
int len = 0;
SIZE_T numRead = 0;
ReadProcessMemory(hProcess, LPBYTE(DataRec->St)-4, &len, 4, &numRead);
if (len > 0)
{
DataSt.resize(len);
ReadProcessMemory(hProcess, DataRec->St, &DataSt[0], len*2, &numRead);
}
CloseHandle(hProcess);
}
// use DataSt as needed...
You're not missing anything. Delphi's WideString is indeed equivalent to BSTR. The value you see in the debugger is a null pointer. Delphi would treat that as an empty string; you should probably treat it the same way.
So you have two different processes - Delphi one (DP) and VS one (VSP). Each has own address space, and valid pointer in the DP is not valid in VSP. That is why <Bad Ptr> (exception?) appears.
BTW, I've noticed that address in VSP is 64-bit. Is Delphi process 64-bit too?
You need some kind of interprocess communication (IPC) through shared memory.
Because you have control over the Service and the MFC program, you could save received data to named memory-mapped file in DLL, then MFC process will open it and read data.
Related
I'm currently studying MFC library and I wonder why should I use GetBuffer member which returns pointer to CString object buffer over other member functions which allow to read and change characters in that object?
For example why should I do (code changes first character of CString object):
CString aString(_T("String")); //new CString object
LPTSTR p = aString.GetBuffer(); //create new pointer to aString buffer
_tcsncpy(p, LPCTSTR(_T("a")), 1); //set first character to 'a'
aString.ReleaseBuffer(); //free allocated memory
Instead of:
CString aStr(_T("String")); //new CString object
aStr.SetAt(0, _T('a')); //set character at 0 position to 'a'
I suppose there is a more appropriate application to use GetBuffer() member, but I can't figure out what it can be... This function requires ReleaseBuffer() to free memory, and I may cause memory leaks when ReleaseBuffer() is not called. Is there any advantage of using it?
Don't use GetBuffer unless you have no alternative. Precisely because of (1) the reason you already know, that it must be followed with ReleaseBuffer which you may forget to do, leading to a resource leak. And (2) you might inadvertently make changes to the underlying data rendering it inconsistent in some way. More often than not the functions GetString, SetString, GetAt and SetAt will do what you need and have no disadvantages. Prefer them.
In above example it is preferable to use the SetAt method.
In some cases you need GetBuffer to directly access the buffer, mainly when used with WinAPI functions. For example, to use ::GetWindowText with WinAPI code you need to allocate a buffer as follows:
int len = ::GetWindowTextLength(m_hWnd) + 1;
char *buf = new char[len];
::GetWindowText(m_hWnd, buf, len);
...
delete[] buf;
The same thing can be done in MFC with CWnd::GetWindowText(CString&). But MFC has to use the same basic WinAPI functions, through GetBuffer. MFC's implementation of CWnd::GetWindowText is roughly as follows:
void CWnd::GetWindowText(CString &str)
{
int nLen = ::GetWindowTextLength(m_hWnd);
::GetWindowText(m_hWnd, str.GetBufferSetLength(nLen), nLen+1);
str.ReleaseBuffer();
}
HRESULT UrlCanonicalize(
_In_ PCTSTR pszUrl,
_Out_ PTSTR pszCanonicalized,
_Inout_ DWORD *pcchCanonicalized,
DWORD dwFlags
);
Example:
LPCTSTR pszURL = URL.c_str();
LPSTR pszOutPut = new CHAR[ strUrl.length ];
DWORD* dwCount = new DWORD[ strUrl.length ];
hRes = UrlCanonicalize( pszURL, pszOutPut,dwCount, URL_ESCAPE_UNSAFE );
Output:
E_INVALIDARG
This API fails and returns E_INVALIDARG every time I try to call it. Please give me a working code snippet to call the UrlCanonicalize function.
If you know the C++ language, the SDK documentation for the function pretty much tells you everything that you need to know:
You pass it a C-style nul-terminated string that contains your URL.
You pass it pointer to a buffer to receive the output string.
You pass it one or more flags that customize the function's behavior.
And finally, it returns to you an HRESULT value, which is an error code. If it succeeds, that value will be S_OK. If it fails, it will be some other error code.
It works like this:
std::wstring originalURL(L"http://www.example.com/hello/cruel/../world/");
// Allocate a buffer of the appropriate length.
// It needs to be at least as long as the input string.
std::wstring canonicalURL(originalURL.length() + 1, L'\0');
DWORD length = originalURL.length() + 1;
// Call the function to modify the string.
HRESULT hr = UrlCanonicalize(originalURL.c_str(), // input string
&canonicalURL[0], // buffer
&length, // pointer to a DWORD that contains the length of the buffer
URL_UNESCAPE | URL_ESCAPE_UNSAFE);
if (SUCCEEDED(hr))
{
// The function succeeded.
// Your canonicalized URL is in the canonicalURL string.
MessageBox(nullptr, canonicalURL.c_str(), L"The URL is:", MB_OK);
}
else
{
// The function failed.
// The hr variable contains the error code.
throw std::runtime_error("The UrlCanonicalize function failed.");
}
If you want to make sure that the buffer is sufficiently long (and avoid having to handle that error), use the constant INTERNET_MAX_URL_LENGTH (declared in WinInet.h) when allocating it:
std::wstring canonicalURL(INTERNET_MAX_URL_LENGTH, L'\0');
DWORD length = INTERNET_MAX_URL_LENGTH;
The code you tried has a couple of problems:
You've incorrectly initialized the dwCount variable. The function wants a pointer, but that doesn't mean you should declare the variable as a pointer. Nor do you want an array; this is a single DWORD value. So you need to declare it as a regular DWORD, and then use the address-of operator (&) to pass the function a pointer to that variable. Right now, you're passing the function garbage, so it's failing.
You're using C-style strings, which you should avoid in C++ code. Use the C++ string class (std::wstring for Windows code), which is exception safe and manages memory for you. As you already know, the c_str() member function gives you easy access to a C-style nul-terminated string like all C APIs want. This works fine, you do not need to use raw character arrays yourself. Avoid new whenever possible.
Potentially, a third problem is that you're trying to use the C++ string type std::string instead of std::wstring. The former is an 8-bit string type and doesn't support Unicode in a Windows environment. You want std::wstring, which is a wide string with Unicode support. It's what all the Windows API functions expect if you have the UNICODE symbol defined for your project (which it is by default).
Here you go:
LPCTSTR pszURL = URL.c_str();
DWORD nOutputLength = strUrl.length * 2 + 32;
LPTSTR pszOutPut = new TCHAR[nOutputLength];
hRes = UrlCanonicalize( pszURL, pszOutPut, &nOutputLength, URL_ESCAPE_UNSAFE);
On the third parameter you provided garbage instead of pointer to initialized value, so you had API failure back. MSDN has it all for you:
A pointer to a value that, on entry, is set to the number of characters in the pszCanonicalized buffer.
I found a nice example how to play with folder selecting dialog: http://bobmoore.mvps.org/Win32/w32tip70.htm - and all this is working except of this example using CString which I can't have on MinGW because it doesn't have stdafx.h. So I must use either string or char*.
But here the problem is that this example uses CString methods: GetBuffer and ReleaseBuffer which I don't have in string object. Is there any other method of passing folder name to folder selection window ?
When dealing with the Windows API and buffers, you can use std::vector<BYTE> for bytes and std::vector<TCHAR> for strings. (TCHAR is defined as wchar_t if UNICODE is defined and char otherwise. This way the code works for both UNICODE and ANSI). When instantiating the vector, give it a size to allocate memory:
// can hold MAX_PATH TCHARs, including terminating '\0'
std::vector<TCHAR> buffer(MAX_PATH);
Now you can treat is almost exactly like a buffer of TCHARs allocated with new or created on the stack.
BROWSEINFO bi = {0};
bi.pszDisplayName = &buffer[0];
However, buffer.size() will always return the full vector length. If you need to know the length of the string stored within the vector, or want to use string related methods,
you can copy it to a std::string:
if( LPITEMIDLIST pidl = SHBrowseForFolder(&bi) ) {
// this way it works for both UNICODE and ANSI:
std::basic_string<TCHAR> folderName(&buffer[0]);
if( SHGetPathFromIDList(pidl,&buffer[0]) ) {
MessageBox(0, &buffer[0], folderName.c_str(), MB_OK);
}
// TODO: free pidl with IMalloc* obtained through SHGetMalloc()
}
Since std::string is just another contiguous container, you could (ab)use that instead of the vector. However, size() will return the number of elements stored in the string, even if they are \0. You would have to resize() the string to the first occurrence of \0 (that is what CString::ReleaseBuffer() does) which is done automatically when you assign the buffer to the string in the above example. Because a string is not meant to be used as a buffer (even if it is technically possible) i strongly recommend using the vector approach.
With std::string you have a read-only access to the underlying representation by using c_str(), but nothing else.
In your case, I think the only option is to use some old-fashioned memory management, and then copy the result in a std::string.
In the CString header file (be it Microsoft's or Open Foundation Classes - http://www.koders.com/cpp/fid035C2F57DD64DBF54840B7C00EA7105DFDAA0EBD.aspx#L77 ), there is the following code snippet
struct CStringData
{
long nRefs;
int nDataLength;
int nAllocLength;
TCHAR* data() { return (TCHAR*)(&this[1]); };
...
};
What does the (TCHAR*)(&this[1]) indicate?
The CStringData struct is used in the CString class (http :// www.koders.com/cpp/fid100CC41B9D5E1056ED98FA36228968320362C4C1.aspx).
Any help is appreciated.
CString has lots of internal tricks which make it look like a normal string when passed e.g. to printf functions, despite actually being a class - without having to cast it to LPCTSTR in the argument list, e.g., in the case of varargs (...) in e.g. a printf. Thus trying to understand a single individual trick or function in the CString implementation is bad news. (The data function is an internal function which gets the 'real' buffer associated with the string.)
There's a book, MFC Internals that goes into it, and IIRC the Blaszczak book might touch it.
EDIT: As for what the expression actually translates to in terms of raw C++:-
TCHAR* data() { return (TCHAR*)(&this[1]); };
this says "pretend you're actually the first entry in an array of items allocated together. Now, the second item isnt actually a CString, it's a normal NUL terminated buffer of either Unicode or normal characters - i.e., an LPTSTR".
Another way of expressing the same thing is:
TCHAR* data() { return (TCHAR*)(this + 1); };
When you add 1 to a pointer to T, you actually add 1* sizeof T in terms of a raw memory address. So if one has a CString located at 0x00000010 with sizeof(CString) = 4, data will return a pointer to a NUL terminated array of chars buffer starting at 0x00000014
But just understanding this one thing out of context isnt necessarily a good idea.
Why do you need to know?
It returns the memory area that is immediately after the CStringData structure as an array of TCHAR characters.
You can understand why they are doing this if you look at the CString.cpp file:
static const struct {
CStringData data;
TCHAR ch;
} str_empty = {{-1, 0, 0}, 0};
CStringData* pData = (CStringData*)mem_alloc(sizeof(CStringData) + size*sizeof(TCHAR));
They do this trick, so that CString looks like a normal data buffer, and when you ask for the getdata it skips the CStringData structure and points directly to the real data buffer like char*
I am writing a C++ DLL that is called by an external program.
1.) I take an array of strings (as char *var) as an argument from this program.
2.) I want to iterate through this array and call a COM function on each element of the string array. The COM function must take a BSTR:
DLL_EXPORT(void) runUnitModel(char *rateMaterialTypeNames) {
HRESULT hr = CoInitialize(NULL);
// Create the interface pointer.
IUnitModelPtr pIUnit(__uuidof(BlastFurnaceUnitModel));
pIUnit->initialiseUnitModel();
int i;
for(i=0; i < sizeOfPortRatesArray; i++)
pIUnit->createPort(SysAllocString(BSTR((const char *)rateMaterialTypeNames[i])));
I think its the SysAllocString(BSTR((const char *)rateMaterialTypeNames[i])) bit that is giving me problems. I get an access violation when the programs runs.
Is this the right way to access the value of the rateMaterialTypeName at i? Note I am expecting something like "IronOre" as the value at i, not a single character.
If you're using Microsofts ATL, you can use the CComBSTR class.
It will accept a char* and create a BSTR from it, also, you don't need to worry about deleting the BSTR, all that happens in the dtor for CComBSTR.
Also, see Matthew Xaviers answer, it doesn't look like you're passing your array of strings into that function properly.
Hope this helps
Because a variable holding a C string is just a pointer to the first element (a char*), in order to pass an array of C strings, the parameter to your function should be a char**:
DLL_EXPORT(void) runUnitModel(char **rateMaterialTypeNames)
This way, when you evaluate rateMaterialTypeNames[i], the result will be a char*, which is the parameter type you need to pass to SysAllocString().
Added note: you will also need to convert the strings to wide chars at some point, as Tommy Hui's answer points out.
If the parameter to the function rateMaterialTypeNames is a string, then
rateMaterialTypeNames[i]
is a character and not a string. You should use just the parameter name itself.
In addition, casts in general are bad. The conversion to a BSTR is a big flag. The parameter type for SysAllocString is
const OLECHAR*
which for 32-bit compilers is a wide character. So this will definitely fail because the actual parameter is a char*.
What the code needs is a conversion of narrow string to a wide string.
const OLECHAR* pOleChar = A2COLE( *pChar );
BSTR str = SysAllocString( pOleChar );
// do something with the 'str'
SysFreeString( str ); // need to cleanup the allocated BSTR