Link to home
Start Free TrialLog in
Avatar of demarcy
demarcy

asked on

Problems assigning memory

Hi.. I'm programming a dialog box to choose a directory. I have some problems on assigning memory...

In some part of the program I have the following method (pay atention in the while loop) :

void TBrowserDlg::FillTreeView( LPSHELLFOLDER lpsf, LPITEMIDLIST lpifq, HTREEITEM hParent )
{
  TV_ITEM tvi;
  TV_INSERTSTRUCT tvins;
  HTREEITEM hPrev = NULL;
  LPENUMIDLIST lpe = NULL;
  LPITEMIDLIST lpi = NULL, lpifqThisItem = NULL;
  LPTVITEMDATA lptvid;
  LPMALLOC lpMalloc;
  HRESULT Resultado;
  HWND hWnd = Arbol->GetParent( );
  ULONG ulFetched;
  char szBuff[MAX_PATH];

  Result = ::SHGetMalloc( &lpMalloc );
  if( SUCCEEDED( Result ) ) {
    Result = lpsf->EnumObjects( hWnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &lpe );
    if( SUCCEEDED( Result ) )
    {
      while( lpe->Next( 1, &lpi, &ulFetched ) == S_OK ) {

        lpMalloc->Free( lpi );
        lpi = 0;
      } // while
    }
  }
  else
    return;
  if( lpe )
    lpe->Release( );
  if( lpi && lpMalloc )
    lpMalloc->Free( lpi );
  if( lpifqThisItem && lpMalloc )
    lpMalloc->Free( lpifqThisItem );
  if( lpMalloc )
    lpMalloc->Release( );
}

I have isolated this loop because I found that in this part is a problem... If I run this program, when I close it, the program crashes, obligating me to reboot the computer... when I comment out that loop, the program works, that is, when I finish it, it closes well, without crashing.

Who can help me in this? do you have a Class to choose a directory? (I have to be able to choose from network neighborhood too, besides local disks, so I have to find the items starting from the desktop)

I'm using Borland C++ 5.0

Thanks in advance
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of demarcy
demarcy

ASKER

I have tested your solution and I have concluded that is a BC++ 5.0 bug or something..... When I used your solution, it worked perfectly, but only while I had the application running... When I closed, the whole computer crashed.

I have commented the second "if" block out and the program worked, that is, it didn't crash on close. It seems that the pMalloc->free isn't deallocating the memory correctly.

Do you know where are patches for borland c++ 5.0? or are there other ways to do it, without using the shell?

Thanks
Jaime
Hmm, that's quite strange - I use the above code often (with VC++), but as it is 'plain' Win32, it should give no problems( i.e., Borland can hardly be blamed, as it is pure Windows API)... doing this without using the shell is like re-inventing the wheel.
Avatar of demarcy

ASKER

Yes, I agree with you, it's quite easy that way, but is there a way to have total control over the dialog box created? for example, title, buttons, etc? I am using this function finally:

void TDirectoriesDlg::evSelRegDir( )
{
  char DirSelected[MAX_PATH];

  memset( DirSelected, 0, MAX_PATH );
  Logs->GetText( DirSelected, MAX_PATH );
  ChooseDirectory( DirSelected, "Registro" );
  Logs->SetText( DirSelected );
}

void TDirectoriesDlg::ChooseDirectory( char* Directorio, char* Que )
{
  BROWSEINFO BrowsingInfo;
  char DirPath[MAX_PATH];
  char FolderName[MAX_PATH];
  char Msg[40];
  LPITEMIDLIST ItemID;

  memset( &BrowsingInfo, 0, sizeof( BROWSEINFO ) );
  memset( DirPath, 0, MAX_PATH );
  BrowsingInfo.hwndOwner      = GetHandle( );
  BrowsingInfo.pszDisplayName = FolderName;
  wsprintf( Msg, "Elija el Directorio de %s", Que );
  BrowsingInfo.lpszTitle      = Msg;
  if( (ItemID = SHBrowseForFolder( &BrowsingInfo )) != NULL ) {
    SHGetPathFromIDList( ItemID, DirPath );
    GlobalFreePtr( ItemID );
    lstrcpy( Directorio, DirPath );
  }
}

This function looks really cute, but it would be better if the application (and computer) don't crash when I close it. As I told you, the dialog box works perfectly, I can choose a directory and everything and the application continue working perfectly too, doing all it has to do without crashing. The problem is when I exit the application. I have never had this sort of problem in my life :(

I was reasearching in the Windows 95 API help and I found some classes which are supposed to do it, they are TShellItem, TShellItemIterator, TPidl, TShellMalloc, etc. Looking at the source codes of them, they do all I was doing at first, so I'd prefer to use them so the shell operations will be well encapsulated, but I don't know how to use that classes because I don't have either examples or books about them. Do you know something about it? in VC++ maybe they exist too, but with names CShellItem, and so on.

An finally may I ask you for a great great favor? To make a last test and to discard a compiler problem, can you make that function a DLL? so I call it from my program to see what happen.

Thanks a lot

You mean I should compile it into a DLL and send it to you - no problem, just give me some time ;-)

BTW: Are you able to find the crash address in a log file or debugger (DrWatson e.g.)?
Avatar of demarcy

ASKER

Yes, I have debugged it and I am able to know exactly in what address is the problem... the fact is that there's a MOV instruction whose source address is already undefined.

I have thought of a solution easier for you. Can you only compile it into an OBJ so I could link it in my project? that is easier than making it a DLL. I don't think the linker is the problem, so it is a good test I can do.

My e-mail is: jstuardo@SoftHome.net

Thanks
>>Can you only compile it into an OBJ

Well, I could do that, but note that the MS .obj format is incompatible with BC++, so a DLL will definitly be better...
Avatar of demarcy

ASKER

Really???? ufff... what a bad thing, so let's try with a DLL :)

Thanks
Avatar of demarcy

ASKER

Ah! and I forgot, what VC++ version are you using?

please, when you program the DLL, can you do something like:

void ChooseDirectory( TDialog* Objeto, char* Directorio, char* Que )
{
  LPMALLOC pMalloc;
  BROWSEINFO BrowsingInfo;
  char FolderName[MAX_PATH];
  char Msg[40];
  LPITEMIDLIST ItemID;

  if  ( SHGetMalloc( &pMalloc ) == S_OK ) {
  // Get help on BROWSEINFO struct - it's got all the bit settings.
    BrowsingInfo.hwndOwner      = Objeto->GetHandle( );
    BrowsingInfo.pidlRoot       = NULL;
    BrowsingInfo.pszDisplayName = FolderName;
    wsprintf( Msg, "Elija el Directorio de %s", Que );
    BrowsingInfo.lpszTitle      = Msg;
    BrowsingInfo.ulFlags        = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;
    BrowsingInfo.lpfn           = NULL;
    BrowsingInfo.lParam         = 0;

    // This next call issues the dialog box.
    if( (ItemID = SHBrowseForFolder ( &BrowsingInfo )) != NULL ) {
      if( SHGetPathFromIDList( ItemID, FolderName ) ) {
        // At this point pszBuffer contains the selected path */.
        lstrcpy( Directorio, FolderName );
        // Free the PIDL allocated by SHBrowseForFolder.
        pMalloc->Free( ItemID );
      }
    }
    // Release the shell's allocator.
    pMalloc->Release();
  }
}

That is to give a little customization to my application. I think instead of TDialog* you have to use CDialog*.

Thanks
Will chage it to read

void ChooseDirectory( HWND hWnd, char* Directorio, char* Que )

so there will be no other libraries involved...

(expect to get it in 1h, but have to finish my DNS setup first - bet, I prefer real programming ;-)