Gary
Gary

Reputation: 89

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.

Upvotes: 1

Views: 275

Answers (3)

Remy Lebeau
Remy Lebeau

Reputation: 596307

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...

Upvotes: 2

MBo
MBo

Reputation: 80187

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.

Upvotes: 1

Rob Kennedy
Rob Kennedy

Reputation: 163287

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.

Upvotes: 2

Related Questions