• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 342
  • Last Modified:

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

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
lowlevel
Asked:
lowlevel
  • 10
  • 10
  • 6
  • +1
1 Solution
 
interCommented:
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
 
JimBob091197Commented:
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
 
interCommented:
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
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
interCommented:
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
 
MadshiCommented:
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
 
MadshiCommented:
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
 
MadshiCommented:
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
 
JimBob091197Commented:
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
 
MadshiCommented:
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
 
JimBob091197Commented:
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
 
MadshiCommented:
Then should everything be fine, now...   :-)
0
 
JimBob091197Commented:
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
 
MadshiCommented:
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
 
JimBob091197Commented:
That's strange, because I tried a IShellFolder sample in D4 and it worked without CoInit & CoUninit.

0
 
JimBob091197Commented:
That's strange, because I tried a IShellFolder sample in D4 and it worked without CoInit & CoUninit.

0
 
MadshiCommented:
That's really strange. Perhaps you've not used CreateComObject but CoCreateInstance?
0
 
interCommented:
So the moral is 'DO NOT CALL RELEASE FOR INTERFACE OBJECTS' -just want to participate ;-)
0
 
JimBob091197Commented:
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
 
JimBob091197Commented:
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
 
MadshiCommented:
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
 
MadshiCommented:
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
 
JimBob091197Commented:
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
 
lowlevelAuthor Commented:
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
 
interCommented:
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
 
lowlevelAuthor Commented:
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
 
JimBob091197Commented:
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
 
interCommented:
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
 
MadshiCommented:
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
 
lowlevelAuthor Commented:
madshi: new question titled "COM reference counting misteries in D3/D4"
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 10
  • 10
  • 6
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now