Using the comdlg32.dll in a 64bit progress client

Posted by PeterWokke on 05-Nov-2014 03:46

The comdlg32.dll does not work to open dialog boxes when we moved from 32bit to 64bit client.

From the internet I have found to replace the defined parameter LONG to INT64.

But this not enough to get tget the dialog box working.

The mempointer for the import parameter I define as follow:

SET-SIZE(lpOfn) = 76. 

/* size */                PUT-LONG (lpOfn, 1) = GET-SIZE(lpOfn).
/* hwndOwner */   PUT-LONG (lpOfn, 5) = QCurrentHWND.
/* hInstance */       PUT-LONG (lpOfn, 9) = 0.
/* lpstrFilter */        PUT-LONG (lpOfn,13) = GET-POINTER-VALUE(lpstrFilter).
/* lpstrCustomFilter */ PUT-LONG (lpOfn,17) = 0.
/* nMaxCustFilter */   PUT-LONG (lpOfn,21) = 0.
/* nFilterIndex */       PUT-LONG (lpOfn,25) = 0.
/* lpstrFile */             PUT-LONG (lpOfn,29) = GET-POINTER-VALUE(lpstrFile).
/* nMaxFile */           PUT-LONG (lpOfn,33) = GET-SIZE(lpstrFile).
/* lpstrFileTitle */      PUT-LONG (lpOfn,37) = 0.
/* nMaxFileTitle */    PUT-LONG (lpOfn,41) = 0.
/* lpstrInitialDir */     PUT-LONG (lpOfn,45) = IF (GET-SIZE(lpstrInitialDir) > 0) THEN GET-POINTER-VALUE(lpstrInitialDir) ELSE 0.
/* lpstrTitle */           PUT-LONG (lpOfn,49) = GET-POINTER-VALUE(lpstrTitle).
/* flags */                   PUT-LONG (lpOfn,53) = Flags.

/* nFileOffset */          PUT-SHORT(lpOfn,57) = 0.
/* nFileExtension */    PUT-SHORT(lpOfn,59) = 0.
/* lpstrDefExt */          PUT-LONG (lpOfn,61) = 0.
/* lCustData */            PUT-LONG (lpOfn,65) = 0.
/* lpfnHook */              PUT-LONG (lpOfn,69) = 0.
/* lpTemplateName */ PUT-LONG (lpOfn,73) = 0.

RUN GetOpenFileNameA (GET-POINTER-VALUE(lpOfn), OUTPUT c-OK).

The external procedure:

PROCEDURE GetOpenFileNameA EXTERNAL "comdlg32.dll":U :
  DEFINE INPUT PARAMETER lpOfn AS {&POINTERTYPE}.
  DEFINE RETURN PARAMETER pReturn AS {&POINTERTYPE}.
END PROCEDURE.

All Replies

Posted by PeterWokke on 05-Nov-2014 03:50

The memory pointer is defined as follows:

DEFINE VARIABLE lpOfn           AS MEMPTR  NO-UNDO.

Posted by Mike Fechner on 05-Nov-2014 03:52

Isn’t SYSTEM-DIALOG GET-FILE a suitable alternative?
 
Or the .NET OpenFileDialog which can be used from classic ABL GUI as well? http://msdn.microsoft.com/en-us/library/system.windows.forms.openfiledialog(v=vs.110).aspx
 
Von: PeterWokke [mailto:bounce-PeterWokke@community.progress.com]
Gesendet: Mittwoch, 5. November 2014 10:47
An: TU.OE.Development@community.progress.com
Betreff: [Technical Users - OE Development] Using the comdlg32.dll in a 64bit progress client
 
Thread created by PeterWokke

The comdlg32.dll does not work to open dialog boxes when we moved from 32bit to 64bit client.

From the internet I have found to replace the defined parameter LONG to INT64.

But this not enough to get tget the dialog box working.

The mempointer for the import parameter I define as follow:

SET-SIZE(lpOfn) = 76. 

/* size */                PUT-LONG (lpOfn, 1) = GET-SIZE(lpOfn).
/* hwndOwner */   PUT-LONG (lpOfn, 5) = QCurrentHWND.
/* hInstance */       PUT-LONG (lpOfn, 9) = 0.
/* lpstrFilter */        PUT-LONG (lpOfn,13) = GET-POINTER-VALUE(lpstrFilter).
/* lpstrCustomFilter */ PUT-LONG (lpOfn,17) = 0.
/* nMaxCustFilter */   PUT-LONG (lpOfn,21) = 0.
/* nFilterIndex */       PUT-LONG (lpOfn,25) = 0.
/* lpstrFile */             PUT-LONG (lpOfn,29) = GET-POINTER-VALUE(lpstrFile).
/* nMaxFile */           PUT-LONG (lpOfn,33) = GET-SIZE(lpstrFile).
/* lpstrFileTitle */      PUT-LONG (lpOfn,37) = 0.
/* nMaxFileTitle */    PUT-LONG (lpOfn,41) = 0.
/* lpstrInitialDir */     PUT-LONG (lpOfn,45) = IF (GET-SIZE(lpstrInitialDir) > 0) THEN GET-POINTER-VALUE(lpstrInitialDir) ELSE 0.
/* lpstrTitle */           PUT-LONG (lpOfn,49) = GET-POINTER-VALUE(lpstrTitle).
/* flags */                   PUT-LONG (lpOfn,53) = Flags.

/* nFileOffset */          PUT-SHORT(lpOfn,57) = 0.
/* nFileExtension */    PUT-SHORT(lpOfn,59) = 0.
/* lpstrDefExt */          PUT-LONG (lpOfn,61) = 0.
/* lCustData */            PUT-LONG (lpOfn,65) = 0.
/* lpfnHook */              PUT-LONG (lpOfn,69) = 0.
/* lpTemplateName */ PUT-LONG (lpOfn,73) = 0.

RUN GetOpenFileNameA (GET-POINTER-VALUE(lpOfn), OUTPUT c-OK).

The external procedure:

PROCEDURE GetOpenFileNameA EXTERNAL "comdlg32.dll":U :
  DEFINE INPUT PARAMETER lpOfn AS {&POINTERTYPE}.
  DEFINE RETURN PARAMETER pReturn AS {&POINTERTYPE}.
END PROCEDURE.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Posted by Matt Gilarde on 05-Nov-2014 05:08

The size of the OPENFILENAME structure is larger in the 64-bit client. You also have to change the offsets for the PUT-LONGs. The HWND and pointer members are 8 bytes wide in the 64-bit client instead of 4 bytes wide as they were in the 32-bit client. You should look at the documentation for the OPENFILENAME structure and calculate the size of the structure and the new offsets based on the data types of the structure members. I can help you with this if you get stuck.

Posted by PeterWokke on 05-Nov-2014 06:03

Matt,

Thank you for your info. I understand the principal of your statement. .

Does it main that the SET-SIZE should be larger then 76.

And that the numbers in the PUT-LONGs and PUT-SHORT need to be adjusted.

I see they cummulate by 4 for a PUT-LONG and by2 for a PUT-SHORT.

For 64bit 8bytes I should increase by 8 for the PUT-LONG.

What should be the increase for the PUT-SHORT, Still 2 or 4.

Thank you kindly to confirm the right answer,

Peter

Posted by jhobson on 05-Nov-2014 06:09

If this is done in C code you can have the compiler generate the offsets for you.

printf ("%d\n", &((OPENFILENAME *) 0)->hInstance);

8 on Win32 and 16 on Win64.

Posted by PeterWokke on 05-Nov-2014 07:05

I have to do it in ABL coding.I have.

&IF PROCESS-ARCHITECTURE EQ 32 &THEN

&GLOBAL-DEFINE POINTERTYPE 'LONG'

&GLOBAL-DEFINE POINTERBYTES 4

&GLOBAL-DEFINE OPENFILENAME_SIZE_VERSION 76

&ELSEIF PROCESS-ARCHITECTURE EQ 64 &THEN

&GLOBAL-DEFINE POINTERTYPE 'INT64'

&GLOBAL-DEFINE POINTERBYTES 8

&GLOBAL-DEFINE OPENFILENAME_SIZE_VERSION 148

&ENDIF

DEFINE VARIABLE iPoint AS INTEGER NO-UNDO.

/* create and initialize an OPENFILENAME structure: */

SET-SIZE(lpOfn) = {&OPENFILENAME_SIZE_VERSION}.

message 'OPENFILENAME_SIZE' {&OPENFILENAME_SIZE_VERSION}

skip    'POINTERBYTES' {&POINTERBYTES}

view-as alert-box.

iPoint = 1.

/* size */              PUT-INT64 (lpOfn, iPoint) = GET-SIZE(lpOfn).

iPoint = iPoint + {&POINTERBYTES}.

/* hwndOwner */         PUT-INT64 (lpOfn, iPoint) = QCurrentHWND.

iPoint = iPoint + {&POINTERBYTES}.

/* hInstance */         PUT-INT64 (lpOfn, iPoint) = 0.

iPoint = iPoint + {&POINTERBYTES}.

/* lpstrFilter */       PUT-INT64 (lpOfn, iPoint) = GET-POINTER-VALUE(lpstrFilter).

iPoint = iPoint + {&POINTERBYTES}.

/* lpstrCustomFilter */ PUT-INT64 (lpOfn, iPoint) = 0.

iPoint = iPoint + {&POINTERBYTES}.

/* nMaxCustFilter */    PUT-INT64 (lpOfn, iPoint) = 0.

iPoint = iPoint + {&POINTERBYTES}.

/* nFilterIndex */      PUT-INT64 (lpOfn, iPoint) = 0.

iPoint = iPoint + {&POINTERBYTES}.

/* lpstrFile */         PUT-INT64 (lpOfn, iPoint) = GET-POINTER-VALUE(lpstrFile).

iPoint = iPoint + {&POINTERBYTES}.

/* nMaxFile */          PUT-INT64 (lpOfn, iPoint) = GET-SIZE(lpstrFile).

iPoint = iPoint + {&POINTERBYTES}.

/* lpstrFileTitle */    PUT-INT64 (lpOfn, iPoint) = 0.

iPoint = iPoint + {&POINTERBYTES}.

/* nMaxFileTitle */     PUT-INT64 (lpOfn, iPoint) = 0.

iPoint = iPoint + {&POINTERBYTES}.

/* lpstrInitialDir */   PUT-INT64 (lpOfn, iPoint) = IF (GET-SIZE(lpstrInitialDir) > 0) THEN GET-POINTER-VALUE(lpstrInitialDir) ELSE 0.

iPoint = iPoint + {&POINTERBYTES}.

/* lpstrTitle */        PUT-INT64 (lpOfn, iPoint) = GET-POINTER-VALUE(lpstrTitle).

iPoint = iPoint + {&POINTERBYTES}.

/* flags */             PUT-INT64 (lpOfn, iPoint) = Flags.

iPoint = iPoint + {&POINTERBYTES}.

/* nFileOffset */       PUT-SHORT (lpOfn, iPoint) = 0.

iPoint = iPoint + 2.

/* nFileExtension */    PUT-SHORT (lpOfn, iPoint) = 0.

iPoint = iPoint + 2.

/* lpstrDefExt */       PUT-INT64 (lpOfn, iPoint) = 0.

iPoint = iPoint + {&POINTERBYTES}.

/* lCustData */         PUT-INT64 (lpOfn, iPoint) = 0.

iPoint = iPoint + {&POINTERBYTES}.

/* lpfnHook */          PUT-INT64 (lpOfn, iPoint) = 0.

iPoint = iPoint + {&POINTERBYTES}.

/* lpTemplateName */    PUT-INT64 (lpOfn, iPoint) = 0.

iPoint = iPoint + 7.

message GET-POINTER-VALUE(lpOfn)

skip 'iPoint ' iPoint

skip STRING(lpOfn) view-as alert-box.

/*CURRENT-WINDOW:SENSITIVE = FALSE.*/

/* run the dialog: */

RUN GetOpenFileNameA (GET-POINTER-VALUE(lpOfn), OUTPUT c-OK).

/*CURRENT-WINDOW:SENSITIVE = TRUE.*/

This still not work.

Should I set

&GLOBAL-DEFINE POINTERBYTES 16

USse for PUT-SHORT increase of 4

&GLOBAL-DEFINE OPENFILENAME_SIZE_VERSION 296

Posted by Matt Gilarde on 05-Nov-2014 08:14

The size of the 64-bit OPENFILENAME structure is 152 bytes. The offsets are listed below. Pointers and handles are aligned on 8-byte boundaries so there is some structure padding after some of the DWORDs.

[code]

  DWORD         lStructSize;    0
  HWND          hwndOwner;    8
  HINSTANCE     hInstance;    16
  LPCTSTR       lpstrFilter;    24
  LPTSTR        lpstrCustomFilter;   32
  DWORD         nMaxCustFilter;    40
  DWORD         nFilterIndex;    44
  LPTSTR        lpstrFile;    48
  DWORD         nMaxFile;    56
  LPTSTR        lpstrFileTitle;    64
  DWORD         nMaxFileTitle;    72
  LPCTSTR       lpstrInitialDir;    80
  LPCTSTR       lpstrTitle;    88
  DWORD         Flags;    96
  WORD          nFileOffset;    100
  WORD          nFileExtension;    102
  LPCTSTR       lpstrDefExt;    104
  LPARAM        lCustData;   112
  LPOFNHOOKPROC lpfnHook;    120
  LPCTSTR       lpTemplateName;    128
  void          *pvReserved;    136
  DWORD         dwReserved;    144
  DWORD         FlagsEx;    148

[code]

Posted by Matt Gilarde on 05-Nov-2014 08:15

You need to add 1 to those offsets because the PUT- functions are (inexplicably) 1-based instead of zero-based.

Posted by PeterWokke on 06-Nov-2014 01:15

Matt,

Thank you kindly for this information.

I see that some position settings increase with 8, with 4 and with 2.

For 8 and 4 I used the PUT-LONG. For 2 I used teh PUT-SHORT function.

I defined the external procedure parameters as INT64.

I made the adjustment to work with 32bit and 64bit using:

&IF PROCESS-ARCHITECTURE EQ 32 &THEN

&GLOBAL-DEFINE POINTERTYPE 'LONG'

&ELSEIF PROCESS-ARCHITECTURE EQ 64 &THEN

&GLOBAL-DEFINE POINTERTYPE 'INT64'

&ENDIF

It works fine now.

Thanks for your time,

Regards, Peter.

Posted by Matt Gilarde on 06-Nov-2014 03:48

You have to use PUT-INT64 to set the values of the structure members which have the "lp" prefix (lpStrFilter, lpstrCustomerFilter, etc.) when PROCESS-ARCHITECTURE = 64. They are pointers and are 8 bytes wide in the 64-bit client. If you use PUT-LONG for them they will be truncated and the code will eventually fail. The reason it appears to work is that the pointer values you've encountered in your testing have been able to fit in 4 bytes (for example, 0x000000007c1234560; this will be truncated to 0x7c1234560 and will still be valid). That won't always be the case and when it happens PUT-LONG will truncate the pointer (so 0x00007b123456abc0 will become 0x000000003456abc0) and the call to GetOpenFileName will crash.

The DWORD members are 4 bytes wide so PUT-LONG is correct for them. WORD members are 2 bytes wide so use PUT-SHORT.

You can't tell how wide a structure member is by looking at the difference between offsets. There is sometimes empty space between structure members. Here's an example:

 DWORD         nMaxFileTitle;    72

 LPCTSTR      lpstrInitialDir;     80

nMaxFileTitle is 4 bytes wide but since lpstrInitialDir is a pointer it must be on an 8-byte boundary. There are 4 bytes of empty space between nMaxFileTitle and lpstrInitialDir to create the alignment.

Posted by Frank Meulblok on 06-Nov-2014 04:00

I'd still suggest replacing the direct DLL calls with the CommonDialog .NET interface (msdn.microsoft.com/.../system.windows.forms.commondialog(v=vs.110).aspx) for convenience's sake

Using that, you shouldn't have to worry about bit-levels, byte alignments, manually building/parsing the memptrs, ANSII vs. wide-character (Unicode) versions of the API etc. as the .NET implementation + ABL support for .NET should take care of that.

This thread is closed