How to convert PVOID to int? - c++

I got a function :
SAFEARRAY FAR* pArray = NULL;
and I get that function :
pServer1->GetDirectMemory(dwAddrBegin, dwAddrEnd, wDisplayWidth, &pArray);
I want to get information from pArray, if i look the structure of it, I have PVOID pvData; that must be contains my information.
How could I get it in a int ?
Old question :
I want to get the data of a PVOID to a int value
I get a SAFEARRAY FAR* pArray and I have only one element so I get ir with a PVOID type like that :
PVOID myData = pArray[0].pvData;
And I try to get the data with the function PtrToInt :
int myNbr = PtrToInt(myData);
But my int (myNbr) doens't get the same value that i can see with my debugger.
So my question is how can i get datas from that SAFEARRAY FAR* pArray or PVOID without using MFC function like SafeArrayAccessData or else.
Thanks

Assuming your array contains ints (use SafeArrayGetVartype to verify), is 1-dimensional (use SafeArrayGetDim) and 0-based (use SafeArrayGetLBound), the correct way to access it is this:
int value;
LONG indices[] = { 0 };
if (FAILED(SafeArrayGetElement(pArray, indices, &value))) {
// getting element failed - probably bad index
}
// value now contains the correct value
You can use SafeArrayAccessData too, but unless you have identified a performance problem, it's better not to.
In general when dealing with OLE structures (VARIANT, SAFEARRAY, etc.) you should always use the provided utility functions. They are part of Windows, not MFC. Here's the reference for arrays:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms221145(v=vs.85).aspx
However, if you can, I strongly recommend you use ATL's wrapper for SAFEARRAY, CComSafeArray. See the documentation and a short blog article showing its usage:
http://msdn.microsoft.com/en-us/library/3xzbsee8.aspx
http://msmvps.com/blogs/gdicanio/archive/2011/02/04/simplifying-safearray-programming-with-ccomsafearray.aspx

Related

Delphi WideString in Visual Studio MFC

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.

How do I call the UrlCanonicalize API function correctly?

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.

Reading a cubin structure from a pointer

I am trying to read the contents a c++ structure(in windows) which has the following format
typedef struct __cudaFatCudaBinaryRec {
unsigned long magic;
unsigned long version;
unsigned long gpuInfoVersion;
char* key;
char* ident;
char* usageMode;
__cudaFatPtxEntry *ptx;
__cudaFatCubinEntry *cubin;
__cudaFatDebugEntry *debug;
void* debugInfo;
unsigned int flags;
__cudaFatSymbol *exported;
__cudaFatSymbol *imported;
struct __cudaFatCudaBinaryRec *dependends;
unsigned int characteristic;
__cudaFatElfEntry *elf;
} __cudaFatCudaBinary;
I have a pointer to this structure (void *ptr)
Now I am looking to read the contents of this structure.
__cudaFatCudaBinary *ptr2=(cudaFatCudaBinary*)ptr;
cout<<ptr->magic;//This works fine
cout<<ptr->key;//This crashes my program..bad pointer results..why?
The above is consistent with all non pointer and pointer members. What am I doing wrong?
ADDED:
ok let me elaborate on the problem. Yes, the address pointed to by "key" is NULL and so it is for all the pointer members. But I know for sure the structure has valid data. It is used by a driver function to generate a handle and it executes fine. All I need is to copy the entire image of the structure and store it in a text file. How would I do it? Why are some of the member fields null? I am thinking of a brute force way to find the address limits of the structure. But the values themselves seem to be invalid when read and I don't know how to go about it!
ADDED 2
Memory Dump of the structure
Thanks !
cout << ptr->key will print as a 0-terminated string whatever key points to, not the pointer itself. If key is NULL or otherwise invalid then this will be undefined behaviour. (In this case a "crash")
If you just want to print the pointer itself make sure you print it as a void* pointer:
cout << static_cast<void*>(ptr->key);
As of CUDA 4.0, the format of this struct drastically changed. The value of magic is now different and gpuInfoVersion is now a pointer to a struct that contains the actual data. For more information, you might want to read this thread.

Why does windows need the size when calling a function?

I am trying to learn a little c++ and I have a silly question. Consider this code:
TCHAR tempPath[255];
GetTempPath(255, tempPath);
Why does windows need the size of the var tempPath? I see that the GetTempPath is declared something like:
GetTempPath(dword size, buf LPTSTR);
How can windows change the buf value without the & operator? Should not the function be like that?
GetTempPath(buf &LPTSTR);
Can somebody provide a simple GetTempPath implementation sample so I can see how size is used?
EDIT:
Thanks for all your answers, they are all correct and I gave you all +1. But what I meant by "Can somebody provide a simple GetTempPath implementation) is that i have tried to code a function similar to the one windows uses, as follow:
void MyGetTempPath(int size, char* buf)
{
buf = "C:\\test\\";
}
int main(int argc, char *argv[])
{
char* tempPath = new TCHAR[255];
GetTempPathA(255, tempPath);
MessageBoxA(0, tempPath, "test", MB_OK);
return EXIT_SUCCESS;
}
But it does not work. MessageBox displays a "##$' string. How should MyGetTempPath be coded to work properly?
Windows needs the size as a safety precaution. It could crash the application if it copies characters past the end of the buffer. When you supply the length, it can prevent that.
Array variables work like pointers. They point to the data in the array. So there is no need for the & operator.
Not sure what kind of example you are looking for. Like I said, it just needs to verify it doesn't write more characters than there's room for.
An array cannot be passed into functions by-value. Instead, it's converted to a pointer to the first element, and that's passed to the function. Having a (non-const) pointer to data allows modification:
void foo(int* i)
{
if (i) (don't dereference null)
*i = 5; // dereference pointer, modify int
}
Likewise, the function now has a pointer to a TCHAR it can write to. It takes the size, then, so it knows exactly how many TCHAR's exist after that initial one. Otherwise it wouldn't know how large the array is.
GetTempPath() outputs into your "tempPath" character array. If you don't tell it how much space there is allocated in the array (255), it has no way of knowing whether or not it will have enough room to write the path string into tempPath.
Character arrays in C/C++ are pretty much just pointers to locations in memory. They don't contain other information about themselves, like instances of C++ or Java classes might. The meat and potatoes of the Windows API was designed before C++ really had much inertia, I think, so you'll often have to use older C style techniques and built-in data types to work with it.
Following wrapper can be tried, if you want to avoid the size:
template<typename CHAR_TYPE, unsigned int SIZE>
void MyGetTempPath (CHAR_TYPE (&array)[SIZE]) // 'return' value can be your choice
{
GetTempPath(SIZE, array);
}
Now you can use like below:
TCHAR tempPath[255];
MyGetTempPath(tempPath); // No need to pass size, it will count automatically
In your other question, why we do NOT use following:
GetTempPath(buf &LPTSTR);
is because, & is used when you want to pass a data type by reference (not address). I am not aware what buf is typecasted to but it should be some pointer type.
Can somebody provide a simple
GetTempPath implementation sample so I
can see how size is used?
First way (based on MAX_PATH constant):
TCHAR szPath[MAX_PATH];
GetTempPath(MAX_PATH, szPath);
Second way (based on GetTempPath description):
DWORD size;
LPTSTR lpszPath;
size = GetTempPath(0, NULL);
lpszPath = new TCHAR[size];
GetTempPath(size, lpszPath);
/* some code here */
delete[] lpszPath;
How can windows change the buf value without the & operator?
& operator is not needed because array name is the pointer to first array element (or to all array). Try next code to demonstrate this:
TCHAR sz[1];
if ((void*)sz == (void*)&sz) _tprintf(TEXT("sz equals to &sz \n"));
if ((void*)sz == (void*)&(sz[0])) _tprintf(TEXT("sz equals to &(sz[0]) \n"));
As requested, a very simple implementation.
bool MyGetTempPath(size_t size, char* buf)
{
const char* path = "C:\\test\\";
size_t len = strlen(path);
if(buf == NULL)
return false;
if(size < len + 1)
return false;
strncpy(buf, path, size);
return true;
}
An example call to the new function:
char buffer[256];
bool success = MyGetTempPath(256, buffer);
from http://msdn.microsoft.com/en-us/library/aa364992(v=vs.85).aspx
DWORD WINAPI GetTempPath(
__in DWORD nBufferLength,
__out LPTSTR lpBuffer
);
so GetTempPath is defined something like
GetTempPath(DWORD nBufferLength, LPTSTR& lpBuffer);
What mean, that compiler passes the value lpBuffer by referenece.

COM API - could not pass "NULL" for a pointer argument

I have a COM API foo, the IDL looks like:
foo([in] unsigned long ulSize, [in, size_is(ulSize)] unsigned char* pData)
when I consume this function with foo(0,NULL);
I get an error - NULL argument passed. Is there a way to workaround this?
Have you tried passing an empty string?
unsigned char Data = 0;
foo(0,&Data);
Don't use char* in COM APIs -- use BSTR instead. Then pass an empty string.
foo([in] unsigned long ulSize, [in] BSTR pData)
...
foo(1, _bstr_t(""));
You should probably mark the char* as as string to get some assistance with the marshaling.
foo([in] unsigned long ulSize, [in,string,size_is(ulSize)] unsigned char* pData)
We don't use the size_is option in the IDL, perhaps it is forcing the issue of having a non NULL address?
foo([in] unsigned long ulSize, [in,string] unsigned char* pData)
I'd certainly recommend using BSTR or SAFEARRAY rather than char. The issue would then be how to handle this empty case best, possibly treating the same as an empty string, or having a separate method.
Passing pointers in COM is very bad form, like passing a pointer using shared memory the (potentially/likely) remote process will not have access to the memory. As such COM tries to help by martialling the actual data for you, but if you have hidden it behind a different data type it won't be martialling the data properly. For instance using wchar_t* it will create a system allocated string available between the processes. or you can do the same and have an interface taking a bstring and pass it the result of a sysallocstring()
Perhaps you could tell us more about the structure you want to use, it might be more appropriate to expand the com interface with objects of this type. Or there may be some other trick in martialling to transfer the data, you can write custom martialling methods to serialize and deserialize the content.
If you're passing in a BSTR you should just pass the BSTR value - they're already length counted (use SysStrLength to find the length).
If you want to pass in a null terminated string, use the [string] attribute as Greg said
But the answer to your actual question is that you need to mark the string parameter as "unique" - that lets the MIDL compiler (and the RPC runtime library) know that it's ok for that parameter to be NULL.
So use:
foo([in, string] unsigned char* pData)
You don't need the length field because it's a null terminated string - so you can use strlen on the string.
foo is probably implemented like this:
HRESULT foo(unsigned long ulSize, unsigned char* pData) {
if (!pData) {
return E_POINTER;
}
...
}
In this case the only workaround is to pass non-NULL pData.