is there a way to find who fired OnExecuteComplete event of TADOConnection? - delphi

I am trying to write an ADO Database profiler in Delphi 7.
it is part of a Delphi project.
I am using OnExecuteComplete event, but on some PCs i get "MSADO15.DLL" Access Violation error.
I have researched and underestand some win version is incompatible or damaged or has different version..
that AV error happened when i use parameters[i].value property of "Command"..
then i decide to write a different type,
now i need a refference to an object who called OnExecuteComplete event in ADOConnection.
if i can reach it, problem will be solved.
i use "Command" and "Recordset" refferences to compare by all of ADO object who linked by this ADOConnection, but some ADO objects has no Recordset..
is there a way to find who fire that event? like Sender?

I could not make out if you are in .Net or not, but in .Net it's easy. Use System.Diagnostics.StackTrace to see the whole stack of calls that lead to your event.
For native code there will probably also be a way to get a stacktrace if you compile in debug mode. It's quite some time since I've written Delphi (or Pascal) code. You could also try profiling with the free AQTime standard which works well with Delphi (both native as well as .Net) which also has a call-graph feature.

i solve it!
i write 2 derrived classes, from ADOQuery and ADOStoredProc.
then i publish Command property of them.
by force convert StoredProcedure to new class, i reach to command prop and compare that by command object of event!
problem solved!
thank you all.

Only WindowsXP,Windows 2003 has problem with "MSADO15.DLL" Access Violation error after read Parameters[i].Value and show recordset. Windows7 has not this problem. Use WillExecute event - it work fine everywhere. In ExecuteComplete you may get recordsAffected from recordset (RecordsAffected variant work wrong). You can get Parameters[i].Value later if Save Parameters to Variant variable and read it after visual components show recordset - use OnButtonClick for example or Timer event. This BUG not fixed at all Delphi versions - and in DelphiXE2 too..

The Sender should give you a clue, if it is not nil. Cast it to TComponent and use its Name property to find out which component fired it:
ShowMessage((Sender as TComponent).Name);
If Sender is nil, a stack trace might help.
Update
Apparently there is no Sender parameter. In this case, the Connection must be the class that fires it, so get its name and other data. You get enough parameters to find out what is happening.

Related

dcc32 Error x.pas(648): E2003 Undeclared identifier: 'x'

So I've tried to add two properties to unit IdMessage.pass. So i've added
TIdMessage = class(TIdBaseComponent)
private
FTaskID: Integer;
FNotificationID: Integer;
protected
... all protected properties and procedures
public
... all protected procedures and functions
property TaskID : Integer read FTaskID write FTaskID;
property NotificationID : Integer read FNotificationID write FNotificationID;
published
...published properties
End;
The unit looks Ok, but when I try to compile a project that uses these two properties I get the Undeclared identifier error. I have no idea why. If I CTRL+CLICK the property at design time, it takes me to the property in the unit, but when I try to build or compile it runs into this error. Any suggestions?
Despite what you say in the comments, you are modifying third party code. In effect you are making a fork. The compiler error is just the first symptom of the trouble that lies ahead. The compiler is not using the code that you have written. The compiler is using a different version.
For sure you can make the fork work by ensuring that the compiler uses your fork rather than the original code. However, you are setting yourself up for a fall. Next time you upgrade Indy, what will happen? Will you be able to merge your fork into the new Indy?
If forking is the best solution, so be it. But it almost certainly is not. We don't know what your actual problem is but forking seems unlikely to be the best way forward. Try to find a design that allows you not to modify the Indy code.

Published interface properties bug and workarounds

I wrote a set of components that link to each other via published interface properties. They are registered and installed in a design package.
Using published interface properties is not that common in Delphi, and thus, unsurprisingly, doesn't seem to work that well.
It works fine when components reside on the same form, however interface property links between components on different forms cause issues.
Unlike object links to components on another form, interface links don't seem to be recognized by IDE. What I mean is best described by an example, when you have 2 forms open in IDE, and have links between components on them, then trying to switch to form view as text (Alt+F12) would cause IDE to correctly complain that:
Module 'UnitXXX.pas' has open descendents or linked modules. Cannot close.
But if the property is an interface then this does not happen, what happens instead is that the link is severed (and that's the best case scenario when you use Notification mechanism to clear references, otherwise you're left with an invalid pointer)
Another problem, likely as a consequence of the same bug is that when you open a project in IDE, the order in which forms will be reopened is undefined, so IDE can try to open a form that contains components that have interface links to components on another form, but that other form is not recreated yet. So this effectively results in either AV or severed links.
Back in 90s while I used Datasets and Datasources I remember similar issues with links between forms disappearing, so this is somewhat similar.
As a temp workaround I added duplicate published properties, for each Interface property I added another that is declared as TComponent. This makes Delphi aware there is a link between forms, but is an ugly workaround to say the least.
So I wonder if there is something I can do to fix this issue ? It's an IDE bug and likely not fixable directly, but perhaps I can override something or otherwise hook in to streaming mechanism to more effectively workaround this bug.
I haven't ever gone so deep into streaming mechanism, but I suspect the Fixup mechanism is supposed to deal with this. There is a csFixups TComponentState so I hope a workaround is possible.
Edit: Using D2007.
Update:
New updated reproducible example uploaded to http://www.filedropper.com/fixupbugproject2
Added property ComponentReference: TComponent so that it's easy to compare and trace interface vs component streaming.
I narrowed the problem down to assembler level which is a bit out of my depth.
In procedure GlobalFixupReferences in classes unit it calls:
(GetOrdProp(FInstance, FPropInfo) <> 0)
which eventually executes:
function TInterfacedComponent.GetInterfaceReference: IInterface;
begin
// uncomment the code bellow to avoid exception
{ if (csLoading in ComponentState) and (FInterfaceReference = nil) then
// leave result unassigned to avoid exception
else
}
result := FInterfaceReference; // <----- Exception happens here
end;
As you can see from the comment, the only way I found to avoid the exception is to leave the result unassigned, but that breaks the functionality since comparison above in GlobalFixupReferences fails due to GetOrdProp <> 0, which severes the link.
tracing deeper the more exact location of exception is in
procedure _IntfCopy(var Dest: IInterface; const Source: IInterface); in system unit
This line in particular raises an read of address 0x80000000
{ Now we're into the less common cases. }
##NilSource:
MOV ECX, [EAX] // get current value
So, why MOV fails and what's wrong with ECX or EAX I have no idea.
To summarize, the problem happens only with published interface properties that have a getter method, and the property points to component on another form/module (and that form/module is not recreated yet). In such case restoring form DFM causes an AV.
I'm pretty sure the bug is in the ASM code in GetOrdProp, but it's beyond my ability to fix, so the
easiest workaround is to use a Field instead of a getter method and read it directly in the property. This is, fortunately good enough for my case currently.
Alternatively, you can declare the property as TComponent instead of interface, then write a TComponentProperty descendant, override ComponentMayBeSetTo to filter component that don't support the required interface. And of course register it using RegisterPropertyEditor

Delphi Win32 Programming/Access Violation problems

I wasn't entirely sure how to name this, so apologies in advance.
You see, I'm trying to teach myself Win32/DirectX programming, utilizing Delphi (my language of choice) using this site - http://rastertek.com/tutindex.html
Of course, the site being all in C++, I have to port it to Delphi. It seemed simple enough, at first. I'm on the second tutorial for DirectX 11 - setting up the framework and getting the initial window to show up.
Now for my actual problem. I was getting Access Violation errors. So I found and started to use MadExcept to try and find out what was going on. So it tells me the lines, but I'm clueless as to how to solve the issues at hand.
I have everything set up to mimic as well as I can the original source code. The only real difference being that in the instances where a pointer to a class for a variable, such as the case with m_input, m_grahics, and system, I made a type for those. So I have the TSystemClass, TInputClass, TGraphicsClass, and then I have PSystemClass, etc. that = ^TSystemClass, etc. I figured that this would make things a bit simpler and more neater. On a side note, I assume it should be said, but I for the construction of the copy constructors made the initial classes inherit from TPersistent so I could use it's Assign procedure.
So, back to the Access Violation errors. So first, the problem was in the main program with system being of type PSystemClass. So for a reason unknown to me, when I tried to use system.create, it was at that very instant, creating the access violation. I then realized however that I wasn't assigning system the system.create. So I tried this, and it said that, and rightfully so I suppose, at compile time an error that the two were incompatible since system.create is of type TSystemClass, and system is of PSystemClass. So I tried typecasting it, and that worked. but once again, still getting the dreaded access violations.
So then I had an odd idea, maybe I should call the regular constructor right from the TSystemClass itself. And I tried, needed to typecast again. So I did. And it worked! No longer an access violation error there! Now... New problem! Or rather in this case "problems". There's 3 things now listed in the call stack in MadExcept. The first one:
m_hinstance := GetModuleHandle(nil);
It's saying that this is causing an access violation error. Though why is this, exactly? From what I understand and have read, if GetModuleHandle is set to null/nil, it should retrieve the handle for the file that called it, right? And from what the documentation says, that should be executable.
However note: I'm not sure if the fact that I have the main program, the systemclass stuff, the inputclass stuff, and the graphicsclass stuff, all in different program/unit files to mimic the nature of the original source code. So is this possibly what's causing it? And if so how would I fix it? By putting all of the code from the unit files into the main program file? Though that, in my own personal opinion, would be quite messy and unintuitive.
The next one baffles me even more.
InitializeWindows(ScreenWidth, ScreenHeight);
I'm not dealing with anything other then a function to register the window class and set things up for the window and all here. So I'm not quite sure what the problem here is since it only deals with 2 parameters and they're defined and all already before it's called. So I'm not quite sure what the problem here is at all and what exactly is causing the access violation.
and then finally the final one is in the main program:
return := system.initialize;
Return is what I used in all instances of the result variable of the original source code, as result is of course a built in variable of all functions.
I suppose if system is never able to properly do what it's meant to do then something could/should happen here. Likewise, because I used TSystemClass.Create (typecasted to PSystemClass) earlier to create system would that do anything here? And is it possibly linked to the other two because they're not able to do their own thing properly?
And on a final note; there is one last thing actually on the call stack in MadExcept.
It says Kernel32.dll in the module section, but aside from the main thread, it lists nothing else. (If this information is needed I'll gladly put it up).
Thanks in advance to anyone who's read this far and I hope to find some help on this problem so I may further my studies.
You're instantiating your classes all wrong. Here's an example from TSystemClass.Initialize:
m_Input := PInputClass(m_Input.create);
That's a variable you declared as a PInputClass.
Earlier, in TSystemClass.Create, you initialized that variable:
m_Input := nil;
So, since you have a null reference, it should be clear that you can't call any methods on it. In particular, you cannot call Create on it. Instead, call Create on the class you want to instantiate: TInputClass.Create.
That constructor returns a value of the type you constructed, a TInputClass. It doesn't return a PInputClass, so your type-cast is wrong. As Cosmin's comment explains, Delphi object variables are already pointers. It's exceedingly rare to have to declare a pointer type based on Delphi classes. The correct code is this:
m_Input := TInputClass.Create;
After that line, you check whether m_Input is null. You never have to do that in Delphi; a constructor either returns a valid object, or it doesn't return at all. If there's a problem constructing an object, the constructor throws an exception and the assignment statement never executes. (The original C++ code does it wrong, too. The new operator hasn't returned a null pointer on failure for over a decade, long before anyone was in a position to start writing a DirectX 11 tutorial.)
You should first of all try to get rid of the TPersistent inheritance. If you want to pass an object to a library its interface should be exactly the same as the original that is used in C++. By inheriting from TPersistent you take a whole lot of load into your class that might be not needed or might even be the reason of your problems.
Additionally it would help if you posted the exact output of the exceptions. Or even the CallStack. That might help tracing down the error.

Access violation after GetInterface/QueryInterface in Delphi

First, I'm very new in Delphi and COM, but I should build COM application in Delphi. I read a lot of articles and notes on the internets, but COM and COM in Delphi are still not clear to me.
My sources - http://www.everfall.com/paste/id.php?wisdn8hyhzkt (about 80 lines).
I try to make a COM Interface and Impl class - it works if I call an interface method from Delphi (I create an impl object via TestClient.Create), but if I try to create an object from outer world (from Java, via com4j) my application crashed with following exception:
Project Kernel.exe raised exception class $C0000005 with
message 'access violation at 0x00000002: read of address 0x00000002'.
If I set a breakpoint in QueryInterface - it breaks, but when I come out from function - all crashes.
What I'm doing wrong? What I still missing? What I can/should read about COM (in Delphi) to avoid dumb questions like this?
There is no need to implement IUnkown.QueryInterface your self. Remove that method from TestComImpl and let TComObject handle it. Also be sure to give the ITestCom interface a GUID.
If the crash is happening after QueryInterface returns, what I would do is put a breakpoint in the Java app when it calls QueryInterface and see what it tries to do next. That'll give you an idea of where to look.
Your comment seems to bear this out. It's calling QueryInterface, getting back a result that says that this interface is good, and trying to use it for something that immediately breaks. But if you comment out the code that tells it the interface is good, it ends up not trying to use the interface, and nothing breaks.
If you're not familiar with Delphi, an access violation usually means a null pointer dereference. Here, it says that your instruction pointer is at memory location 0x000002. That probably means that you somehow tried to call a virtual method (or an interface method) on an object that hasn't been constructed yet.
Hope that helps!
I made a dll with COM from scratch and
I use DllRegisterServer - it gave me a possibility to control server registration (over
TComObjectFactory.RegisterClassObject in my first attempt)
I remove QueryInterface from my TestComImpl
Com4j supports only STA (Apartment) threading model (I assume RegisterClassObject uses
MTA)
So if class registered as Apartment (STA) or Both - com4j can create instances.
Thanks everyone for help!

Invalid pointer operation in TMonitor.Destroy

I'm currently working on porting an existing Delphi 5 application to Delphi 2010.
It's a multithreaded DLL (where the threads are spawned by Outlook) that loads into Outlook. When compiled through Delphi 2010, whenever I close a form I run into an "invalid pointer operation" inside TMonitor.Destroy... the one in system.pas, that is.
As this is an existing and kinda complex application, I have a lot of directions to look into, and the delphi help doesn't even document barely documents this particular TMonitor class to begin with (I traced it to some Allen Bauer posts with additional information) ... so I figured I'd first ask around if anyone had encountered this before or had any suggestions on what could cause this problem.
For the record: I am not using the TMonitor functionality explicitly in my code, we are talking a straight port of Delphi 5 code here.
Edit Callstack at the moment the problem occurs:
System.TMonitor.Destroy
System.TObject.Free
Forms.TCustomForm.CMRelease(???)
Controls.TControl.WndProc(???)
Controls.TWinControl.WndProc((45089, 0, 0, 0, 0, 0, 0, 0, 0, 0))
Forms.TCustomForm.WndProc(???)
Controls.TWinControl.MainWndProc(???)
Classes.StdWndProc(15992630,45089,0,0)
Forms.TApplication.ProcessMessage(???)
The pointer to the System.Monitor instance of each object is stored after all the data fields. If you write too much data to the last field of an object it could happen that you write a bogus value to the address of the monitor, which would most probably lead to a crash when the destructor of the object attempts to destroy the bogus monitor. You could check for this address being nil in the BeforeDestruction method of your forms, for a straight Delphi 5 port there shouldn't be any monitors assigned. Something like
procedure TForm1.BeforeDestruction;
var
MonitorPtr: PPMonitor;
begin
MonitorPtr := PPMonitor(Integer(Self) + InstanceSize - hfFieldSize + hfMonitorOffset);
Assert(MonitorPtr^ = nil);
inherited;
end;
If this is a problem in your original code you should be able to detect it in the Delphi 5 version of your DLL by using the FastMM4 memory manager with all checks activated. OTOH this could also be caused by the size increase of character data in Unicode builds, and in that case it would only manifest in DLL builds using Delphi 2009 or 2010. It would still be a good idea to use the latest FastMM4 with all checks.
Edit:
From your stack trace it looks like the monitor is indeed assigned. To find out why I would use a data breakpoint. I haven't been able to make them work with Delphi 2009, but you can do it easily with WinDbg.
In the OnCreate handler of your form put the following:
var
MonitorPtr: PPMonitor;
begin
MonitorPtr := PPMonitor(Integer(Self) + InstanceSize - hfFieldSize + hfMonitorOffset);
MessageDlg(Format('MonitorPtr: %p', [pointer(MonitorPtr)]), mtInformation,
[mbOK], 0);
DebugBreak;
// ...
Now load WinDbg and open and run the process that calls your DLL. When the form is created a message box will show you the address of the monitor instance. Write down the address, and click OK. The debugger will come up, and you set a breakpoint on write access to that pointer, like so:
ba w4 A32D00
replacing A32D00 with the correct address from the message box. Continue the execution, and the debugger should hit the breakpoint when the monitor gets assigned. Using the various debugger views (modules, threads, stack) you may get important information about the code that writes to that address.
An invalid pointer operation means your program attempted to free a pointer, but there was one of three things wrong with it:
It was allocated by some other memory manager.
It had already been freed once before.
It had never been allocated by anything.
It's unlikely that you'd have multiple memory managers allocating TMonitor records, so I think we can rule out the first possibility.
As for the second possibility, if there's a class in your program that either doesn't have a custom destructor or that doesn't free any memory in its destructor, then the first actual memory deallocation for that object could be in TObject, where it frees the object's monitor. If you have an instance of that class and you attempt to free it twice, that problem could appear in the form of an exception in TMonitor. Look for double-free errors in your program. The debugging options in FastMM can help you with that. Also, when you get that exception, use the call stack to find out how you got to TMonitor's destructor.
If the third possibility is the cause, then you have memory corruption. If you have code that makes assumptions about the size of an object, then that could be the cause. TObject is four bytes larger as of Delphi 2009. Always use the InstanceSize method to get an object's size; don't just add up the size of all its fields or use a magic number.
You say the threads are created by Outlook. Have you set the IsMultithread global variable? Your program normally sets it to True when it creates a thread, but if you're not the one creating threads, it will remain at its default False value, which affects whether the memory manager bothers to protects its global data structures during allocation and deallocation. Set it to True in your DPR file's main program block.
After a lot of digging it turns out I was doing a nice (read: horrifying, but it has been properly doing its job in our delphi 5 apps for ages)
PClass(TForm)^ := TMyOwnClass
somewhere deep down in the bowels of our application framework. Apparently Delphi 2010 has some class initialization to initialize the "monitor field" that now didn't happen, causing the RTL to try and "free the syncobject" upon form destruction because getFieldAddress returned a non-nil value. Ugh.
The reason why we were doing this hack in the first place was because I wanted to automatically change the createParams on all form instances, to achieve an iconless resizable form. I will open up a new question on how to do this without rtl-breaking hacks (and for now will simply add a nice shiny icon to the forms).
I will mark Mghie's suggestion as the answer, because it has provided me (and anyone reading this thread) with a very large amount of insight. Thanks everyone for contributing!
There are two TMonitor in Delphi:
System.TMonitor; which is a record, and is used for thread synchronization.
Forms.TMonitor; which is a class representing an attached monitor (display device).
System.TMonitor is added to Delphi since Delphi 2009; so if you are porting a code from Delphi 5, what your code was using was Forms.TMonitor, not System.TMonitor.
I think the class name is referenced without unit name in your code, and that is making the confusion.

Resources