0

I have searched and cannot find anything that answers my question. If the phrasing of my question is incorrect please advise and I will rephrase it. I do not profess to be an expert in pointers, but what I am doing seems fairly straight forward and within the guidance provided here:

Pointers and Pointer Types (Delphi)

I have a DLL written in Delphi. It is called from a C++ application (sfms_trayicon.exe). The function in question is of type Pointer and it has one parameter, a pointer. The pointer is passed as a generic pointer and then cast to a hWnd pointer. It is then de-referenced to a variable of type hWnd. Here is the actual function code:

    function sfms_ui_init(FhWnd: Pointer): Pointer;
    var
      pCallinghWnd: ^hWnd;          // hWnd pointer type

    begin
      try
        // Get the hWnd passed as a generic pointer
        pCallinghWnd := FhWnd;           // Cast the general pointer to a hWnd pointer
        CallinghWnd := pCallinghWnd^;    // De-reference the pointer (CallinghWnd is a global var of type hWnd)
      finally

      end;
    end;

The pointer passed to the function is valid. The assignment to a hWnd pointer type works. The de-referncing occasionally works, but most times generates and access violation: enter image description here

My question, and I hope it is specific enough, why would the line de-referencing the pointer work occasionally, but most times throw an access violation? I guess the follow up would be, what do I need to do to make it work?

Thanks

8
  • 1
    Please don't describe the calling code, and assure us that it is correct. You could be wrong. Please show it. Please show a complete minimal reproducible example. Both sides of the interop please. The DLL code can be cut down to 20 lines, the calling code similarly. Obvious causes for the mismatch are that the calling convention is wrong (this looks like register) or that you are not passing what you think you are passing. For instance, it is surely a mistake to pass the address of a variable holding an HWND. Pass an HWND by value. Also, your function does not return anything, despite promising to do so. Commented Jan 6, 2016 at 14:02
  • 1
    .... and your try/finally is pointless. It looks like you are trying stuff at random. Time to step back. Commented Jan 6, 2016 at 14:05
  • @David Heffernan This is a development exercise, the try/finally will get fleshed out later or removed, just there as a place mark. Not trying stuff at random, although getting to that point:) I think you are probably correct in that the pointer parameter is not what it should be (although the function executes some of the time without the AV). I have looked at Remy's advice which I think is sound and will get the author of the C++ routine to simply pass a windows handle as the parameter in the first instance. Thank you for your response. Commented Jan 7, 2016 at 0:19
  • Well, that advice is found in my comment too. Commented Jan 7, 2016 at 3:23
  • @David Heffernan, Yes it is and I should have also stated that when I said 'I think you are probably correct'. I should also have said I have looked at Remy's and your advice which I think is sound..... It wasn't meant as a slight. Commented Jan 7, 2016 at 4:15

1 Answer 1

3

Delphi and C++ are strongly-typed languages. Since your function expects a pointer to an HWND as input, declare it as such, eg:

type
  PHWND = ^HWND;

function sfms_ui_init(FhWnd: PHWND): Pointer;
begin
  CallinghWnd := FhWnd^;
  //...
end;

Or better:

function sfms_ui_init(var FhWnd: HWND): Pointer;
begin
  CallinghWnd := FhWnd;
  //...
end;

There is no point in passing an HWND variable by pointer/reference, unless the function needs to modify the caller's HWND variable directly. An HWND is already a pointer, so it should be passed by value in most cases:

function sfms_ui_init(FhWnd: HWND): Pointer;
begin
  CallinghWnd := FhWnd;
  //...
end;

why would the line de-referencing the pointer work occasionally, but most times throw an access violation? I guess the follow up would be, what do I need to do to make it work?

Without seeing your C++ code, there is no way to really answer that. However, since your function expects a pointer to an HWND, but is accepting it as a generic untyped Pointer, chances are the C++ code is not passing the correct memory address to that pointer. For instance, if the C++ code is doing this:

HWND hWnd = ...;
sfms_ui_init(hWnd); // passing wrong address!

When it should be doing this instead:

HWND hWnd = ...;
sfms_ui_init(&hWnd); // passing correct address!

Pointer in Delphi translates to void* in C++, which has no type information. An HWND is already a pointer, and any pointer can be passed to a void*, so the compiler allows the assignment, but it causes a runtime error.

All the more reason to get rid of untyped pointers and use typed pointers instead. Using proper types lets the C++ compiler validate that the correct kind of pointer value is being passed to the function, eg:

// given: function sfms_ui_init(FhWnd: PHWND): Pointer;
// or: function sfms_ui_init(var FhWnd: HWND): Pointer;

HWND hWnd = ...;
sfms_ui_init(hWnd); // compiler error!
sfms_ui_init(&hWnd); // OK

// given: function sfms_ui_init(FhWnd: HWND): Pointer;

HWND hWnd = ...;
sfms_ui_init(hWnd); // OK
sfms_ui_init(&hWnd); // compiler error!
Sign up to request clarification or add additional context in comments.

1 Comment

You are exactly correct. In hindsight passing a pointer to a pointer makes no real sense. The author of the C++ routine wanted to keep his application OS agnostic since it may be ported to OSX, but the fact that we have not yet tried simply passing a windows handle rather than a pointer to a pointer and casting it to a typed pointer and dreferncing that to a windows handle seems an overly convoluted way of just passing a windows handle. Thank you for your well thought out response. Whilst it seems a BFO (blinding flash of the obvious) it has indeed put the issue into a sensible perspective.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.