0
votes

I have a delphi application that uses BTMemoryModule and imports/calls functions from a DLL. The DLL is written in C/C++.

The delphi application sends an original pwidechar (array of 4 bytes or array of widechars) to a function.

I have no C/C++ pseudo code but it looks like this:

type
 TMyFunc = function ( p  : pointer ): pointer; stdcall;

procedure anynamehere();
var
 Addr     : TMyFunc;
 MyString : WideString;
begin
 [...]
  Addr := BTMemoryGetProcAddress('mydll.dll', 'ExportedFunc');
  MyString := 'TEST';
 [...]
 ExportedFunc (pwidechar(MyString));
 MessageBoxW (0, pwidechar(MyString), '', 0);
end;

The DLL should now have the original pointer to the MyString var. The procedure in the delphiapp stays active (until the dll ExportedFunc is finished). So the MyString var gets NOT disposed after the procedure ends. My question now is: Is it possible to CHANGE the value of MyString within the DLL? (technically possible...) But How? The string is null terminated so the user knows how long the pointer length is. But if the C++ DLL changes the value , doesn't have the user also alloc new space or something? Or does this happen automatically?

Thanks for your help.

3
What is your actual requirement? And are you at liberty to modify the DLL?David Heffernan

3 Answers

3
votes

The DLL is welcome to change the pointed-to memory if it wants, and it doesn't need to know the address of MyString, either. It only needs to know the address stored in MyString, which is exactly what you pass to it already. Since the function receives a pointer to a null-terminated array of WideChar values, the function should be declared like this:

void* __stdcall ExportedFunc(wchar_t* arg);

It can find out the length of the buffer with wcslen, and then modify the contents of the buffer in the usual ways. For example:

{
  size_t const len = wcslen(arg);
  for (size_t i = 0; i < len; ++i)
    if (arg[i] == 'a')
      arg[i] = 'e';
  return 0;
}

You can have it return some other pointer value if you wish, but since the caller ignores it, it doesn't really matter in this situation.

When the caller assigned a value to MyString, space was allocated automatically by the OS on the program's behalf via SysAllocString. The caller then passes that buffer to the DLL, and the DLL can modify it. The caller doesn't need to do anything special with the buffer afterward. Delphi will call SysFreeString automatically when the calling function ends and MyString goes out of scope.

You could also remove the PWideChar type cast and declare the function to receive a WideString in Delphi, a BSTR in C++. You could do all the same string manipulations in the DLL in addition to using SysStringLen instead of wcslen. You could pass MyString directly to the function:

ExportedFunc(MyString);
2
votes

The C++ code can alter the content of the pwidechar array that is passed in, but it would not be able to change the length of the string as understood by delphi, as the C++ code doesn't understand delphi-style strings natively. All it receives is a wchar * parameter.

If you wanted to make major changes to the string e.g. make it longer, then you would need to allocate at least as much space as you wanted in the caller by using SetLength(MyString, size), and then check the length on return, so you then call SetLength(MyString, retSize) on the string to make it the returned size.

Again, usual caveats against buffer overruns and the like.

I notice that the function returns a pointer; if the C++ code is allocating memory using new(), then you will have no possibility of managing this memory from the Delphi code as the two memory allocation systems are different.

2
votes

The DLL is passed a pointer to the buffer. It is perfectly possible for the DLL to modify that buffer. The DLL can modify any of the 4 wide characters that your code passes to it. It could also modify the fifth character, the null-terminator.

However, the DLL cannot create a new buffer and have the calling code see that new buffer.