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.
The memory pointer is defined as follows:
DEFINE VARIABLE lpOfn AS MEMPTR NO-UNDO.
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.
Flag this post as spam/abuse.
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.
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
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.
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
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]
You need to add 1 to those offsets because the PUT- functions are (inexplicably) 1-based instead of zero-based.
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.
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.
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.