Solved

Access Violations after the last piece of code has been walked through...

Posted on 1998-09-16
29
284 Views
Last Modified: 2010-08-05
See question-title; where would I start to debug, if the access violation only occurs AFTER that last piece of code has executed?

system: Delphi 4.01, NT4, SP3, IE4
project-type: COM Automation (ActiveX) server.
0
Comment
Question by:lowlevel
  • 10
  • 10
  • 6
  • +1
29 Comments
 
LVL 5

Expert Comment

by:inter
Comment Utility
This was happen to me before, it is due to some
IXXXX object that I try to call release. So "try not call .release methof for the interface objects" is my suggestion
igor
0
 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
Hi Igor

Interesting comment.  I've been having some strange Access Violations too.  I use SHGetMalloc to get an instance of IMalloc, but then... do I call _Release or not?  I don't always get AV but it's also after my program has closed.  I will try removing all _Release and let you know what happens...  (It just seems wrong!  When will the IMalloc object be freed?)

(Similar problems with IShellFolders too.)

JB
0
 
LVL 5

Expert Comment

by:inter
Comment Utility
Actually you are right my friend. But my proffesional opinion is that the LOCAL objects should not be released. Look at the following example, before I have comented the release things it will do just as you and lowlevel suggested(this one creates a short cut on the desktop, I once translated this almost directly from SDK)

uses
  shlobj, ComObj, ActiveX;

const
  IID_IPersistFile: TGUID = (
    D1:$0000010B;D2:$0000;D3:$0000;D4:($C0,$00,$00,$00,$00,$00,$00,$46));

// CreateLink - uses the shell's IShellLink and IPersistFile interfaces
//   to create and store a shortcut to the specified object.
//
// lpszPathObj - address of a buffer containing the path of the object
// lpszPathLink - address of a buffer containing the path where the
//   shell link is to be stored
// lpszDesc - address of a buffer containing the description of the
//   shell link
//
//C:\WINNT\Profiles\All Users\Start Menu\Programs\Startup
//C:\WINDOWS\Start Menu\Programs\Startup

function CreateLink(lpszPathObj, lpszPathLink, lpszDesc : PChar):HRESULT;
var
    hres : HRESULT;
    psl : IShellLink;
    ppf : IPersistFile;
    wsz : array[0..MAX_PATH] of WORD;
begin
    // Get a pointer to the IShellLink interface.
    hres := CoCreateInstance( CLSID_ShellLink, nil,
        CLSCTX_INPROC_SERVER, IID_IShellLinkA, psl);
    if (SUCCEEDED(hres)) then
    begin

        // Set the path to the shortcut target, and add the
        // description.
        if not SUCCEEDED(psl.SetPath(lpszPathObj)) then
          MessageBeep(0);

        if not (NOERROR =psl.SetDescription(lpszDesc)) then
          MessageBeep(0);

       // Query IShellLink for the IPersistFile interface for saving the
       // shortcut in persistent storage.
        hres := psl.QueryInterface(IID_IPersistFile, ppf);

        if (SUCCEEDED(hres)) then
        begin
            // Ensure that the string is ANSI.
            MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1,
                @wsz, MAX_PATH);
            // Save the link by calling IPersistFile::Save.
            hres := ppf.Save(@wsz, TRUE);
//            ppf._Release; //this line
        end;
//        psl._Release; //and this line
    end;
    Result := hres;
end;

I think since ppf and psl are declared as local static variables(although pascal treat all such class variables as dynamic) the memory allocator tries to dispose them upon exiting the procedure. Since we already release them with release, it raises and error on a code line that can not be seen. This is what I think of it, lets discuss on...,(I hear that you are asking me whether I declare them globally ;-) And since this is just a guess I do not know if it is same for all interface objects.

nice discussion,
regards, igor
0
 
LVL 5

Expert Comment

by:inter
Comment Utility
I have moved the local vars to unit scope, then shortcut creating became succesfull. But the program gives the error upon termination...which indirectly support the guess...
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
Delphi (version 3 or higher) DOES REALLY FREE all interface correctly. Calling _Release might bring Delphi into problems. It's the same with strings. Delphi handles string allocation and deallocation for you. You don't have to do nothing. So you don't have with interfaces, either. Delphi 4 even treats dynamic arrays (with all sub-arrays and sub-strings and ...) correctly (I've tested that).

inter,

I've just worked a little bit on your example, showing some Delphi specific COM (and wide string) syntax enhancements:

function CreateLink(pathObj, pathLink, desc: string) : HRESULT;
var sl : IShellLink;
    pf : IPersistFile;
begin
  // Get a pointer to the IShellLink interface.
  sl:=CreateComObject(CLSID_ShellLink) as IShellLink;
  // Set the path to the shortcut target, and add the description.
  if sl.SetPath       (PChar(pathObj))<>NOERROR then MessageBeep(0);
  if sl.SetDescription(PChar(desc   ))<>NOERROR then MessageBeep(0);
  // Query IShellLink for the IPersistFile interface for saving the shortcut in persistent storage.
  pf:=sl as IPersistFile;
  result:=pf.Save(wideString(pathLink),true);
end;

Hope this helps... Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
Or even shorter:

function CreateLink(pathObj, pathLink, desc: string) : HRESULT;
var sl : IShellLink;
begin
  // Get a pointer to the IShellLink interface.
  sl:=CreateComObject(CLSID_ShellLink) as IShellLink;
  // Set the path to the shortcut target, and add the description.
  if sl.SetPath       (PChar(pathObj))<>NOERROR then MessageBeep(0);
  if sl.SetDescription(PChar(desc   ))<>NOERROR then MessageBeep(0);
  // Query IShellLink for the IPersistFile interface for saving the shortcut in persistent storage.
  result:=(sl as IPersistFile).Save(wideString(pathLink),true);
end;

I love Delphi...   :-)
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
Oooops, two little corrections:

(1) result:=(sl as IPersistFile).Save(PWideChar(wideString(pathLink)),true);
(2) Application has to call "CoInitialize(nil)" at initialization and "CoUninitialize" at finalization.
0
 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
OK, so this makes sense, and my app isn't crashing when I remove all "_Release".

But what happens when you use the same local variable more than once in a procedure?
Do you free all instances?  All instances except the last one you use?  None?

Mmm...  just when I thought I was understanding this stuff!!  :-)
Bye,
JB
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
JimBob,

there are two situations. If you've something like
  sf:=CreateComObject(IShellFolder) as IShellFolder;
  ...
  sf:=CreateComObject(IShellFolder) as IShellFolder;
in the same procedure, Delphi frees the first object for you. But there's another situation I'm not so sure about it. If you've somthing like
  sf:=CreateComObject(IShellFolder) as IShellFolder;
  sf.BindToObject(pidl,nil,IID_IShellFolder,pointer(sf));
I'm not sure what delphi does, because BindToObject wants to have a pointer as last parameter. Perhaps Delphi handles this right, too. I just don't know. Because of that I'm usually doing something like
  sf1:=CreateComObject(IShellFolder) as IShellFolder;
  sf1.BindToObject(pidl,nil,IID_IShellFolder,pointer(sf2));
  sf1:=sf2;
to work around this problem.

Regards, Madshi.
0
 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
Ok, well that's OK because when I use IShellFolder's BindToObject I use 2 different objects:
RootFolder.BindToObject(pidlCurrent, nil, IID_IShellFolder, Pointer(CurrentFolder);

Cheers,
JB
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
Then should everything be fine, now...   :-)
0
 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
Good.  Thanks Madshi - you've cleared up some stuff for me that I've been wondering about for a long time.  Now, does Delphi 4 work the same way?  I would assume that D4 works like D3.
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
Yes, D4 works like D3 in this matter. I think there was nothing to make better. The only difference I recognized is that with D4 I had to call "CoInitialize/CoUninitialize" which was not necessary with D3.
0
 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
That's strange, because I tried a IShellFolder sample in D4 and it worked without CoInit & CoUninit.

0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
That's strange, because I tried a IShellFolder sample in D4 and it worked without CoInit & CoUninit.

0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
That's really strange. Perhaps you've not used CreateComObject but CoCreateInstance?
0
 
LVL 5

Expert Comment

by:inter
Comment Utility
So the moral is 'DO NOT CALL RELEASE FOR INTERFACE OBJECTS' -just want to participate ;-)
0
 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
Yes, this seems to be the lesson.  :-)
I've removed ALL my _AddRef & _Release and I haven't had a single AV since!

LowLevel: Are you stil with us??
0
 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
Madshi: I actually don't use either CreateComObject or CoCreateInstance in my app, so that explains it.  I only use the following:

SHGetMalloc (to get IMalloc)
SHGetDesktopFolder (to get IShellFolder)
MyShFolder.BindToObject (to get IShellFolders)
MyShFolder.GetUIObject (to get IContextMenu, etc.)
MyShFolder.EnumObjects (to get IEnumIDList)
etc...

JB
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
JimBob,

yes, that will be the reason. I'm using SHGetDesktopFolder myself. But there's no such function for IShellLink. So if you ever use it, with Delphi 4 you'll probably have to do ConInit. No problem, of course...

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
P.S: You should not use _Release, but you HAVE to make sure that all the pidls (used with IShellFolder) are freed correctly. I think you're doing that!?

procedure FreePidl(var pidl: PItemIDList);
var malloc : IMalloc;
begin
  if (pidl<>nil) and (SHGetMalloc(malloc)=NOERROR) then begin
    malloc.Free(pidl);
    pidl:=nil;
  end;
end;
0
 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
Hi Madshi

Yes, I am freeing the pidls, that's why I get IMalloc.

I will remember to use CoInit when using IShellLink (& others too).  Thanks again.

Bye,
JB
0
 
LVL 1

Author Comment

by:lowlevel
Comment Utility
all:
I've checked out this answer yesterday, and it seems to work. I haven't solved all my problems yet, but that's due to the fact that my object hierarchy is getting a bit complex :)

inter: you were the first one, answer the question please so I can grade it.

jimBob : i'm still here :)
you said that you also removed most _addrefs. Assume two interfaces; iA and iB, implemented by txA and txB. Suppose iB is a property of iA, and iA is responsible for creating an instance of iB. Code in txA would be
procedure txA.initialize;
begin
..
  fB:=txB.create; //fB is a class private var of txB
  fB._addref;
  //optionally, init fB
..
end;

if I don't do the addRef, I get an AV because delphi's exit-procedure handler (I think that's it) kills my fB instance..
That's why I found it particularly weird, that I must call _addref at init but not _release at destroy. Seems inconsistent to me.


0
 
LVL 5

Expert Comment

by:inter
Comment Utility
Thanks,
the other friends have much contribution, I'd like to
ask their opinion on grading if you do not mind...(sorry to hang you for a while)
regards, igor

0
 
LVL 1

Author Comment

by:lowlevel
Comment Utility
np, I chose for you because I don't think EE supports multiple ppl getting credit for an answered Q. I chose you because you were first.

but i'm open to suggestions...

0
 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
Good idea, although I think Madshi has tought us (me!!) something.

It's the spirit of Ex-Ex which is more important than who gets the points.

JB
0
 
LVL 5

Accepted Solution

by:
inter earned 100 total points
Comment Utility
Ok then -I record a favor for both David and Madshi-
So the anser is:(quick reference for the others)
SINCE DELPHI SUCCESFULLY FREES ALL THE INTERFACE OBJECT DON NOT CALL _RELEASE METHOD
regards, igor-thanks ever body-
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
lowlevel,

no problem, give the points to igor (inter)...     :-)

I'm interested in you _addref problem. I don't understand why Delphi should release this fB when exiting txA.initialize. Delphi should do this only if fB were a local variable of txA.initialize.
Could you post a more complete example (compilable if possible) of what you're doing? Then I'll look a little bit closer at this "phenomenon".

Regards, Madshi.
0
 
LVL 1

Author Comment

by:lowlevel
Comment Utility
madshi: new question titled "COM reference counting misteries in D3/D4"
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now