Delphi Application Error with Ole in a DLL - delphi

I have a Com Object, setup/create/working from a DataModule.
creating/running/freeing the Datamodule from an Application works with out an issue.
but putting the datamodule into a DLL works fine the first time, runing the com object etc.. but after a few calls with out restarting the application, this error appears.
Error Message image http://darkaxi0m.name/so/errormessage.GIF
There is a fare bit of code in the App, so i cant post it all,
I have tried MadExcept in both the Application and Dll, with no luck. The IDE Breaks at a point that does not seem much help...
alt text http://darkaxi0m.name/so/cpubreak.gif
this is the code that handles the DataModule, the same function is used in the Application and the Dll in both tests
function GetAmount( Amount : integer; var Info: PChar): integer; stdcall;
var
tempInfo: string;
workerDM : TworkerDM;
begin
Result := 0;
workerDM := TworkerDM.Create(nil);
try
tempInfo:= Info;
Result := workerDM.GetAmount(Amount, tempInfo);
StrPCopy(Info, tempInfo);
finally
workerDM.Free;
end;
end;
i would like to blame the Ole Object, but it works fine out of the Dll
I'm at a loss to even think where to start looking.

In the finally, you are calling Free, but should call workerDM.Free.

I don't believe this question can be answered any more.
The project has be scraped, and the object that produce the error no longer used.
My Delete Requests have gone unanswered.
So this is now my answer.

Related

Delphi word automation: Create Ole Object inside Dll

Does anyon know how to create word ole object in DLL.
I have one application that load a DLL which in turn create word ole object.
My application crash every time.
MSWord:= CreateOleObject('Word.Application');
Assuming that Word is installed, then the primary reason why you code might fail is that COM has not been initialized in the calling thread. That is not something that should be attempted from the DLL, because you want the DLL to be able to work with consumers that have already initialized COM.
So, the correct way to tackle this is to state as part of the DLL's interface contract that COM must be initialized by the caller. Typically by calling CoInitialize or CoInitializeEx.
One further comment, is that it if the application crashes, that suggests that you error handling is broken. All the functions in your DLL should take steps to catch any exceptions and convert into error codes to be returned to the caller. I suspect that you have not done this and are throwing a Delphi exception out of the DLL. You must never do that.
Note that I have given a broad and general answer. That matches the broad nature of the question, and the fact that there are few details in the question. If you had provided an MCVE we could have offered a more detailed response.
As DavidH points out, CoInitialize has to be called in the calling thread.
A point to watch out for in connection with the main thread of a VCL application is that whether a VCL application calls CoInitialize automatically depends on whether it uses the ComObj unit: if it does the CoInitialize is called via TApplication.Initialize and the InitComObj routine in ComObj; if it does not, you must call it (or CoInitializeEx) yourself.
The easy way to test this is to call the DLL from a TApplication-less console application - this will avoid being misled by ComObj being used some other than your main unit.
Suppose you have a DLL that contains the following exported procedure:
procedure CreateWordDoc;
var
DocText : String;
MSWord,
Document : OleVariant;
begin
MSWord := CreateOleObject('Word.Application');
MSWord.Visible := True;
Document := MSWord.Documents.Add;
DocText := 'Hello Word!';
MSWord.Selection.TypeText(DocText);
end;
then you could call it like this:
program WordCaller;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows, ActiveX;
type
TWordProc = procedure;
var
LibHandle : THandle;
WordProc : TWordProc;
begin
CoInitialize(Nil);
LibHandle := LoadLibrary('WordDll.Dll');
try
if LibHandle <> 0 then begin
try
WordProc := GetProcAddress(LibHandle, 'CreateWordDoc');
if Assigned(WordProc) then
WordProc;
finally
FreeLibrary(LibHandle);
end;
end;
finally
CoUnInitialize;
Readln;
end;
end.

Delphi F2084 Internal Error: AV07953449-R26D7474C-0

In my project, i'm trying to connect one more UNIT, named Lang_Unit.pas with some classes and procedures, but, while compiling the Project, Delphi gives unknown error called "[dcc32 Fatal Error] Lang_Unit.pas(5): F2084 Internal Error: AV07953449-R26D7474C-0".
And the point is that, what if i will close my project, or remove this connected UNIT, error is not getting away.
And if i will create clear default VCL Application, its still gives this error.
And only when i'm restarting my Delphi 2010, error is getting away.
But, if i will try to edit something in the code, this error is comes again...
What is problem ? Everything was works fine, im not touched nothing.
I've just turned off my PC, then after some time turned it ON and opened my Project and edited my code, then i see this error...
If Its will help, here is my Lang_Unit.pas code :
unit Languages_UNIT;
interface
Uses
System.Generics.Collections, IniFiles;
Type
TLanguages_List = Class
private
LangType:string;
LangDescription:string;
LangFile:TIniFile;
public
Constructor Create(LType,LDes:string; LFile:TiniFile);
Function GetLangType:string;
Function GetDescription:string;
Function GetStructure:TIniFile;
End;
TLanguages_Controller = Class
public
Function GetStructureByType(RequestedType:string; LangList:TObjectList<TLanguages_List>):TIniFile;
Function TypeExists(RequestedType:string; LangList:TObjectList<TLanguages_List>):Boolean;
Procedure LoadLanguage(RequestedType:string; LangList:TObjectList<TLanguages_List>);
End;
implementation
uses Unit1;
Constructor TLanguages_List.Create(LType,LDes:string; LFile:TiniFile);
Begin
LangType:=LType;
LangDescription:=LDes;
LangFile:=LFile;
End;
Function TLanguages_List.GetLangType:string;
Begin
Result:=LangType;
End;
Function TLanguages_List.GetDescription:string;
Begin
Result:=LangDescription;
End;
Function TLanguages_List.GetStructure:TIniFile;
Begin
Result:=LangFile;
End;
Function TLanguages_Controller.GetStructureByType(RequestedType:string; LangList:TObjectList<TLanguages_List>):TIniFile;
var
i:integer;
Begin
For i := 0 to LangList.Count-1 Do
Begin
IF(LangList[i].GetLangType=RequestedType) Then
Begin
Result:=LangList[i].GetStructure;
Break;
End;
End;
End;
Function TLanguages_Controller.TypeExists(RequestedType:string; LangList:TObjectList<TLanguages_List>):Boolean;
var
i:integer;
GOTYA:Boolean;
Begin
GOTYA:=False;
For i := 0 to LangList.Count-1 Do
Begin
IF(LangList[i].GetLangType=RequestedType) Then
Begin
GOTYA:=True;
Break;
End;
End;
IF(GOTYA) Then
Result:=True
Else
Result:=False;
End;
Procedure TLanguages_Controller.LoadLanguage(RequestedType:string; LangList:TObjectList<TLanguages_List>);
var
i:integer;
SLS:TIniFile;//SELECTED LANGUAGE STRUCTURE
CS:string;//CURRENT SECTION
Begin
//GET SELECTED LANGUAGE STRUCTURE
For i := 0 to LangList.Count-1 Do
Begin
IF(LangList[i].GetLangType=RequestedType) Then
Begin
SLS:=LangList[i].GetStructure;
Break;
End;
End;
//START LOADING SELECTED LANGUAGE
//TABS SECTION LOAD
CS:='TABS';
SD_DEFNAME:=SLS.ReadString(CS,'Speed_Dials','Speed_Dials');
Form1.goleft.Hint:=SLS.ReadString(CS,'Back','Back');
Form1.goright.Hint:=SLS.ReadString(CS,'Forward','Forward');
REFLESHBTN_TEXT:=SLS.ReadString(CS,'Reflesh','Reflesh');
STOPBTN_TEXT:=SLS.ReadString(CS,'Stop','Stop');
//PAGE_POPUP SECTION LOAD
CS:='PAGE_POPUP';
Form1.ChromiumPopup.Items[0].Caption:=SLS.ReadString(CS,'Forward','Forward');
Form1.ChromiumPopup.Items[1].Caption:=SLS.ReadString(CS,'Back','Back');
Form1.ChromiumPopup.Items[2].Caption:=SLS.ReadString(CS,'Reflesh','Reflesh');
Form1.ChromiumPopup.Items[3].Caption:=SLS.ReadString(CS,'Copy_Link','Copy Link');
Form1.ChromiumPopup.Items[4].Caption:=SLS.ReadString(CS,'Save','Save');
Form1.ChromiumPopup.Items[5].Caption:=SLS.ReadString(CS,'Print','Print');
Form1.ChromiumPopup.Items[6].Caption:=SLS.ReadString(CS,'view_source','View Source');
Form1.ChromiumPopup.Items[7].Caption:=SLS.ReadString(CS,'code_debug','Code Debug');
End;
end.
Internal error means that the compiler itself is in a 'confused' state.
The way to get out of this is to:
Save your code in a safe location for later reference.
Restart Delphi
Revert the source code to the last known good state by undoing your last edits, or by loading a temp save file.
You can find the previous files in the _backup folder.
Make sure to set file type to any file.
In order to have Delphi generate a save file upon compilation you need to enable autosave
It's a good idea to have Delphi keep more than the default 10 saves. I like to set it to the max: 90.
Just keep restarting Delphi, and compile a previous version, until the internal error goes away.
Then you just recreate the code in a slightly different manner.
(You did save the original code right?)
I also had this problem (in Delphi 10 Berlin). It started shortly after I changed the name of a component in a frame. It also seemed very persistent. However I found the by right clicking the project and selecting 'Clean' followed by 'Build' solved the problem.
I had this issue with my system drive's memory less than 300mb left. It was especially choking in the cache folder. Prior to this error I had a sensible error (fatal error DBG) when I was attempting to recurse already async functions into a larger async function in a big multi threaded application. The compiler just gave up!(perhaps for circular references and too many subfunctions of a function) The two errors may not be related. But after freeing the system drive to about 2 Gigs upon restart and correcting the above mistake, I did a clean then it compiled just fine.
In my case, the solution for the F2084 error code was to change the encoding from ANSI to UTF8.
In my case, I made several packages that related one to another, and all were built as design and run time packages. But one day, I changed some of them to run-time only packages. After that I experienced this kind of error. It took me hours to realize that I should rebuilt all other related packages. After doing that, the error was away eventually.

Calling a function in DLL so slow

My program have several worker threads that calling a function in a dynamically loaded DLL file. The performance is slower than calling function in EXE file. My program made using Delphi. I don't use ShareMM. The function in DLL has many routines to read file into memory. The used calling convention is stdcall. Actually, the speed is very poor!
I have no idea since I just learned about using DLL. So what should I do to optimize the performance/speed of my program/DLL?
Sorry if my question is non sense. I am sure there is nothing wrong with my exe, I just moved my functions into DLL and the performance be slower. Please ignore disk/memory cache factor as I have mentioned the routines of my DLL.
Edited:
This is how my program load the DLL
DLLHandle := LoadLibrary(pwchar(path));
if DLLHandle <> 0 then
#CheckFile := GetProcAddress(DLLHandle, 'CheckFile');
In my worker threads, I always check the function using if Assigned(CheckFile) then then call CheckFile function.
Here illustration of my function
type
TCheckFile = function(const FileName: string; var FileType: WideString)
: Boolean; stdcall;
var
CheckFile: TCheckFile ;
Now, the code in DLL
function CheckFile(const FileName: string; var FileType: WideString)
: boolean; stdcall;
var
testCheckFile: TBla;
begin
Result := false;
testCheckFile := TBla.Create;
try
if testCheckFile.DoSomeRoutine(FileName, FileType) then
Result := true;
finally
testCheckFile.Free;
end;
end;
exports CheckFile;
begin
IsMultiThread := true;
end.
What my DLL do? It plays with TFileStream like convert file to pointer.
I hope there is something wrong with my loading code and the calling code.
Code that resides in a DLL runs at just the same speed as code that resides in the host executable. It is exceedingly unlikely that moving code to a DLL will result in a discernible drop in performance.
However, you state in comments to the question that you have also ported from Delphi 2007 to Delphi XE2. That is almost certainly the change that resulted in the performance drop.
When measuring and comparing performance it is simply crucial to change one thing at a time so that you remove any possibility for confounding factors.
Maybe the problem is having to do with: " dynamically loaded DLL file". Dynamic is ok, but once you load it, keep it loaded right? If you keep loading/unloading for every function call, it's going to be slow (and a lot slower in the debugger!)

Delphi - Form in DLL - Hints not showing

I have a Delphi form inside a DLL (I know that this restricts the use of the DLL to Delphi but this is not a problem in this case).
The DLL exports a function ShowForm that looks roughly like this:
procedure ShowForm (App : TApplication);
begin
OldApp := Application;
try
Application := App;
MyForm := TMyForm.Create (nil);
try
MyForm.ShowModal;
finally
FreeAndNil (MyForm);
end;
finally
Application := OldApp;
end;
end;
Now on the form I use a TAdvOfficeHint (from the TMS component pack). Unfortunately the hints do not show up.
Am I missing something here? How can I make the form behave exactly as it would if I showed it from the main application?
Thanks!
I don't know TAdvOfficeHint but I guess it hooks Application.OnShowHint to set its own THintWindowClass, and even if both the main executable and the DLL are linking in the TMS unit, they each have their own copy of the class which is where things go wrong.
Assigning Application is not enough: there are other global variables, like Screen, Mouse, etc. Others are even hidden in the implementation so I'd say your chances to make the form behave exactly as from the main application are slim.
Just found the reason why it does not work. As TOndrej states, TAdvOfficeHinthooks Application.OnShowHint and internally executes the following line of code:
FHintInfo.Assign (AHintInfo);
Assign internally uses a dynamic type check
if (Source is TAddvHintInfo) then ...
which fails due to the separate type registries of the DLL and the main application.
I have run into this problem a few times now and maybe I really have to switch to runtime packages to avoid all this stuff.
Anyway, if there's anything I can do to prevent this, please comment.
Wrong setting of Application.
Try this and see if it solves your problem:
procedure ShowForm (AppHandle : THandle);
begin
OldAppHandle := Application.Handle;
try
Application.Handle := AppHandle;
........
finally
Application.Handle := OldAppHandle;
end;
end;
I guess in Delphi 2006 and later versions you can call System.ShareMemoryManager method in the EXE code, so that its memory manager is shared with other modules loaded in the process memory space.

TIdHTTP in Indy 10

I used to use Indy back in the Delphi 6 days, and I am playing with Indy 10 now. What I want to do is incredibly simple, but I don't see a simple way of doing it, so I must be missing something.
What I want to do is something like this:
Here is the actual code I am using:
procedure TForm1.btnGetURLClick(Sender: TObject);
begin
moHeader.Lines.Clear;
moBody.Lines.Clear;
try
moBody.text := IdHttp1.Get(edURL.text);
finally
end;
end;
When the request is complete, the http_result should contain the HTML from the URL specified. This doesn't seem to work however, so I get the feeling I should perhaps be using the IOHandler property or the OnWork event of the component - however the usage doesn't seem obvious to me, and I couldn't find any working examples with google. I am sure this is something that has been done before, so any help would be appreciated.
Additional Information:
In the spirit of being more specific, I want to know:
1. Am I doing this right to begin with (or did I miss something?).
2. If so, why might it not be working.
3. It is always possible that there is a bug in the combination of compiler/os/Indy I am using. (Although it should be working).
I should mention, I always get a popup "Connection Closed Gracefully". This seems to be an exception, and it could be interfering with the result of the function. I attempted to trap this with a TRY...FINALLY, but it doesn't work. Probably because Indy is triggering the exception in the background after the Get method runs I suppose.
Finally, here is a screencast of the program running to clear up any confusion:
http://screencast.com/t/NDMzNTQ5
I expect the HTML to fill the second memo box.
i think you have the TIdHTTP.HandleRedirects property set to false, if you get the error "HTTP/1.1 302 Found" you can try this
var
http_result:string;
Begin
IdHTTP1.HandleRedirects:=True;
http_result := IdHTTP1.Get('http://www.google.com');
End;
Another option, would be to use synapse. This is all that is needed to retrieve a webpage using this library:
uses
...,HTTPSEND;
var
Result : TStrings;
if HTTPGetText('http://www.google.com',Result) then
// do something with result
Synapse is a lightweight TCPIP library. The library is being actively maintained and the current version runs fine in Delphi 2009/2010. It is NOT a component based framework, so it is very easy to use with other threading techniques (OmniThreadLibrary or AsyncCalls for example).
You have to set the property HandleRedirects to true.
There's no need for a form, using GExperts components to code I got this:
var
IdHTTP: TIdHTTP;
IdHTTP := TIdHTTP.Create(Self);
with IdHTTP do
begin
Name := 'IdHTTP';
AllowCookies := True;
HandleRedirects := True;
HTTPOptions := [hoForceEncodeParams];
end;
Just paste this in your unit, it should be all you need.
Iirc if the website redirects, you also need to override some handler (onredirect or so). But this was also the case in indy9 iirc.
This question has lingered open for quite some time, so I am closing it out. My solution was to just use Synapse, as one of the posters suggested. It works on windows/Linux/Mac OS with minimal modifications, and works fine in libraries/threads.

Resources