Solved

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

Posted on 1998-09-16
29
306 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
ID: 1339857
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
ID: 1339858
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
ID: 1339859
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
Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

 
LVL 5

Expert Comment

by:inter
ID: 1339860
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
ID: 1339861
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
ID: 1339862
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
ID: 1339863
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
ID: 1339864
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
ID: 1339865
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
ID: 1339866
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
ID: 1339867
Then should everything be fine, now...   :-)
0
 
LVL 5

Expert Comment

by:JimBob091197
ID: 1339868
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
ID: 1339869
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
ID: 1339870
That's strange, because I tried a IShellFolder sample in D4 and it worked without CoInit & CoUninit.

0
 
LVL 5

Expert Comment

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

0
 
LVL 20

Expert Comment

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

Expert Comment

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

Expert Comment

by:JimBob091197
ID: 1339874
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
ID: 1339875
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
ID: 1339876
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
ID: 1339877
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
ID: 1339878
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
ID: 1339879
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
ID: 1339880
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
ID: 1339881
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
ID: 1339882
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
ID: 1339883
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
ID: 1339884
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
ID: 1339885
madshi: new question titled "COM reference counting misteries in D3/D4"
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

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

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Delphi : could not find program, '...exe' 2 193
how to center only a line in richedit? 4 61
control image tags in a string ? 12 142
Installshield for Embarcadero EX 10.1 Berlin 4 60
The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
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…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …
Established in 1997, Technology Architects has become one of the most reputable technology solutions companies in the country. TA have been providing businesses with cost effective state-of-the-art solutions and unparalleled service that is designed…

827 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