Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

getsavefilename and ivf 2017 r2

Brooks_Van_Horn
New Contributor I
734 Views

I've been using the following code:

type(T_OPENFILENAME) ofn
character(*),parameter :: filter_spec = &
  "All Files"C//"*.*"C//""C
character(512) :: file_spec = ""C

    lnth = Strlen (myBuffer)
    if (lnth < 2) Then
       file_spec = "TempFile.txt"C
    else
       file_spec = myBuffer
    end if

    lDlg = gdlg
    hwDlg = gdlg%HWND
    call getcwd(cdir)
    cd2 = trim(cdir)
    ofn%lStructSize = SIZEOF(ofn)
    ofn%hwndOwner = ghWndMain
    ofn%hInstance = ghInst
    ofn%lpstrFilter = loc(filter_spec)
    ofn%lpstrCustomFilter = NULL
    ofn%nMaxCustFilter = 0
    ofn%nFilterIndex = 1 ! Specifies initial filter value
    ofn%lpstrFile = loc(file_spec)
    ofn%nMaxFile = sizeof(file_spec)
    ofn%nMaxFileTitle = 0
    ofn%lpstrInitialDir = loc(cd2)
    ofn%lpstrTitle = loc(""C)
    ofn%Flags = ior(OFN_PATHMUSTEXIST, OFN_NOVALIDATE)
    ofn%lpstrDefExt = loc("txt"C)
    ofn%lpfnHook = NULL
    ofn%lpTemplateName = NULL

    file_spec = Trim(AdjustL(myBuffer)) // ""C
    lnth = StrLen(file_spec)

    bret = GetSaveFileName(ofn)     !<===== BOMB

in ivf 2016 with no problems. But now with 2017 r2 I get a break when calling it. This an x84 application and it is single threaded. I'm running in debug mode and my system has 32GB of RAM. My processor is an Intel i7-4770 running at 3.4GHz. I'm running within MS vs2013 Community Edition and my OS is Win 10 x64. I am using the Intel Parralel Studio XE Composer Edition.

Anyone have any ideas?

Thanks,

Brooks

0 Kudos
10 Replies
Steve_Lionel
Honored Contributor III
734 Views

This is not a complete source. I suggest you try to construct a reproducer by starting with the GETOPENFILENAME sample (it's pretty clear your code is based on that), and gradually tweak it to match your current code. There's stuff you have left out that might be relevant, I tested the GETOPENFILENAME sample and it works fine.

0 Kudos
IanH
Honored Contributor II
734 Views

The snippet isn't compilable, so there may be other issues, but the parameter associated with the current working directory is not null terminated.  Different versions of the compiler will lay things out in memory in different ways, which means things like a missing null termination will result in different behaviour.  Perhaps `cd2 = trim(cdir) // ACHAR(0)` instead of your line 16.


 

0 Kudos
JVanB
Valued Contributor II
734 Views

Don't know much about this, but a couple of things I would try are:

  1. Don't use an initializer for file_spec, rather set its value with an assignment statement. This only matters if the procedure is invoked twice. Hmm... there is some contradictory logic involving file_spec, so maybe this is irrelevant.
  2. As a named constant, filter_spec doesn't necessarily have a LOC. You might want to assign a variable with filter_spec and use the LOC of the variable.
  3. Hopefully you have checked that cd2 has something valid in it.
  4. I would set lpstrFileTitle to NULL rather than LOC(""C) and anyhow I would give the LOC of a variable rather than that of a literal.
  5. All of the above probably will have no effect, but certainly I would use keyword syntax to construct the structure in one statement. That way you know that all members are set to some known value. Some of them might have been set to zero in previous environments but are now set to garbage. This really could cause a crash.

I assume that you mean that the program crashes at that last line so you can't use GetLastError or CommDlgExtendedError to investigate the cause of the problem.

 

0 Kudos
Brooks_Van_Horn
New Contributor I
734 Views

Complete subroutine:

Subroutine Browse (myBuffer)
!$=Browse                               
!$                            
!$
!$ Browse           is invoked by:
!$    Dlgchanged       Saveall
!$
!$ Browse           invokes:
!$    Func   Adjustl        Func   Char           Module Comdlg32       Module Gdi32
!$    Subr   Getcwd         Func   Getsavefilena  Module Ifwin          Func   Index
!$    Func   Ior            Module Kernel32       Func   Loc            Module Mstrlen
!$    Module Pearsonglobal  Func   Sizeof         Func   Strlen         Func   Trim
!$    Module User32         Module Xtransf
!$
!$=Browse
use ifwin
use user32
use gdi32
use kernel32
use comdlg32
use mStrLen

Implicit None


Character(*),Intent(inout)::  myBuffer

integer(4)::      ilen, lnth
Integer(bool)::   bret
character(512)::  cdir, cd2
type(T_OPENFILENAME) ofn
character(*),parameter :: filter_spec = &
  "All Files"C//"*.*"C//""C
character(512) :: file_spec = ""C

    lnth = Strlen (myBuffer)      ! lnth = 10   myBuffer = "Sample.Txt"C
    if (lnth < 2) Then
       file_spec = "TempFile.txt"C
    else
       file_spec = myBuffer
    end if

    call getcwd(cdir)   ! ok
    cd2 = trim(cdir)    ! cd2 = 'C:\Users\Brooks\Desktop\Projects\Pearson\Pearson  '
    ofn%lStructSize = SIZEOF(ofn)       ! = 152
    ofn%hwndOwner = NULL
    ofn%hInstance = NULL
    ofn%lpstrFilter = loc(filter_spec)
    ofn%lpstrCustomFilter = NULL
    ofn%nMaxCustFilter = 0
    ofn%nFilterIndex = 1 ! Specifies initial filter value
    ofn%lpstrFile = loc(file_spec)
    ofn%nMaxFile = sizeof(file_spec)  
    ofn%nMaxFileTitle = 0
    ofn%lpstrInitialDir = loc(cd2)
    ofn%lpstrTitle = NULL
    ofn%Flags = OFN_PATHMUSTEXIST
    ofn%lpstrDefExt = loc("txt"C)
    ofn%lpfnHook = NULL
    ofn%lpTemplateName = NULL

    bret = GetSaveFileName(ofn)
    if (bret == 0) then
       return
    end if
    ilen = INDEX(file_spec,CHAR(0))
    myBuffer = file_spec(1:ilen-1)
    return
End Subroutine Browse

I tested the getopenfilename sample and it works fine for a console app. This subroutine is part of a large app that has 70+ subroutines and a winmain program. I then added it to generic and it works, so I don't know what to do. I guess I have a lot of debugging before I can resolve this, but thank to all for your comments.

Brooks

0 Kudos
Steve_Lionel
Honored Contributor III
734 Views

In your original post you said this was an "x84 application". Did you mean x86 or x64? If x86, did you try building it as x64?

0 Kudos
JVanB
Valued Contributor II
734 Views

As I said, I would try filling in all structure members first:

module mStrLen
   use ISO_C_BINDING
   implicit none
   private
   public StrLen
   interface
      function StrLen(str) bind(C,name='strlen')
         import
         implicit none
         integer(C_SIZE_T) StrLen
         character(KIND=C_CHAR), intent(in) :: str(*)
      end function StrLen
   end interface
end module mStrLen

Subroutine Browse (myBuffer)
!$=Browse                               
!$                            
!$
!$ Browse           is invoked by:
!$    Dlgchanged       Saveall
!$
!$ Browse           invokes:
!$    Func   Adjustl        Func   Char           Module Comdlg32       Module Gdi32
!$    Subr   Getcwd         Func   Getsavefilena  Module Ifwin          Func   Index
!$    Func   Ior            Module Kernel32       Func   Loc            Module Mstrlen
!$    Module Pearsonglobal  Func   Sizeof         Func   Strlen         Func   Trim
!$    Module User32         Module Xtransf
!$
!$=Browse
use ifwin
use mStrLen
use ifport

Implicit None

Character(*),Intent(inout)::  myBuffer

integer(4)::      ilen, lnth
Integer(bool)::   bret
character(512)::  cdir, cd2
type(T_OPENFILENAME) ofn
character(*),parameter :: Pfs = &
  "All Files"C//"*.*"C//""C
character(len(Pfs)) :: filter_spec = Pfs
character(*), parameter :: Pfx = 'txt'//achar(0)
character(len(Pfx)) :: lpstrDefExt = Pfx
character(512) :: file_spec

    file_spec = achar(0)
    lnth = Strlen (myBuffer)      ! lnth = 10   myBuffer = "Sample.Txt"C
    if (lnth < 2) Then
       file_spec = "TempFile.txt"C
    else
       file_spec = myBuffer
    end if

    cdir = ''
    bret = getcwd(cdir)   ! ok
    cd2 = trim(cdir)//achar(0)    ! cd2 = 'C:\Users\Brooks\Desktop\Projects\Pearson\Pearson  '
    ofn = T_OPENFILENAME( &
       lStructSize = SIZEOF(ofn), &       ! = 152
       hwndOwner = NULL, &
       hInstance = NULL, &
       lpstrFilter = loc(filter_spec), &
       lpstrCustomFilter = NULL, &
       nMaxCustFilter = 0, &
       nFilterIndex = 1, & ! Specifies initial filter value
       lpstrFile = loc(file_spec), &
       nMaxFile = len(file_spec), &
       lpstrFileTitle = NULL, &
       nMaxFileTitle = 0, &
       lpstrInitialDir = loc(cd2), &
       lpstrTitle = NULL, &
       Flags = OFN_PATHMUSTEXIST, &
       nFileOffset = 0, &
       nFileExtension = index(file_spec,'.',BACK=.TRUE.), &
       lpstrDefExt = loc(lpstrDefExt), &
       lCustData = NULL, &
       lpfnHook = NULL, &
       lpTemplateName = NULL, &
       pvReserved = NULL, &
       dwReserved = 0, &
       FlagsEx = 0)

    bret = GetSaveFileName(ofn)
    if (bret == 0) then
       return
    end if
    ilen = INDEX(file_spec,CHAR(0))
    myBuffer = file_spec(1:ilen-1)
    return
End Subroutine Browse

 

0 Kudos
Brooks_Van_Horn
New Contributor I
734 Views

Dear Repeat Offender,

Thanks for the code. I tried it but still it didn't help. Here is what vs2013 debugger says after I hit continue, enter the directory and filer that I want and click save:

'PDC.exe' (Win32): Unloaded 'C:\Windows\System32\xmllite.dll'
The thread 0x23f4 has exited with code 0 (0x0).
7376 0000000000000000 ENTER: DllCanUnloadNow
ShellStreams: Detach

=======================================
VERIFIER STOP 0000000000000900: pid 0x256C: A heap allocation was leaked.

    0000025B216DAA10 : Address of the leaked allocation. Run !heap -p -a <address> to get additional information about the allocation.
    0000025B08F56570 : Address to the allocation stack trace. Run dps <address> to view the allocation stack.
    0000025B1F3F6FCC : Address of the owner dll name. Run du <address> to read the dll name.
    00007FFCC4D70000 : Base of the owner dll. Run .reload <dll_name> = <address> to reload the owner dll. Use 'lm' to get more information about the loaded and unloaded modules.


=======================================
This verifier stop is continuable.
After debugging it use `go' to continue.

=======================================

PDC.exe has triggered a breakpoint.

The program '[9580] PDC.exe' has exited with code 0 (0x0).


Debug looks fine before and within subroutine Browse before the break. I've got everything turned on in debug checking, like zeroing arrays and array bounds checking but I haven't figured it out yet.

Brooks

0 Kudos
Brooks_Van_Horn
New Contributor I
734 Views

Also, I'm on x64 not x86.

Brooks

0 Kudos
andrew_4619
Honored Contributor II
734 Views

I have found using the T_OPENFILENAME structure a bit like swimming in mud. There are many options and permutations and also the behaviour varies dependent on which version of windows is running. Just as a matter of interest does it work if you set lpstrInitialDir=NULL?

0 Kudos
Brooks_Van_Horn
New Contributor I
734 Views

Andrew, done it both ways. Same resul;t.

Brooks

0 Kudos
Reply