I have many users using my application. However if I do some update, which I put on the server, not all of them are willing to update it (they sometimes afraid of changes they do not want to accustom).
So I speculate, how to force them to launch the latest application. There are surely several ways how to do it, but I have heard, that it is possible to launch an application stored in a blob field of a database.
Does anybody knows how it can be accomplished? (I am using MySQL database)
thanx
Without judging on meaningful or nonsense ....
You could use uExecFromMem .....
There is a Memoryleak in this unit which can be fixed by adding:
ResumeThread(PI.hThread);
Result := PI.hThread;
FreeMem(pFile); // added here
end;
an example call using a TBlobField would be
var
ms:TMemoryStream;
begin
ms:=TMemoryStream.Create;
try
TBlobField(YouDBBlobField).SaveToStream(ms);
ms.Position := 0;
ExecuteFromMem(Application.ExeName,'',ms.Memory); // pointing to an existing executable
finally
ms.Free;
end;
end;
My advice is to use libraries.
You can have a small main executable file (some kind of "launcher"), which won't do nothing but launch external .dll fields. Just like a kernel does load modules at runtime (think about how Windows or Linux work).
Then you download an updated version of a .dll, stop and unload the old one, then load and initialize the new version.
Of course, your code has to be "clean", with proper startup and shutdown functions for each .dll.
But I suspect it would be much less error prone than ExecuteFromMem(). In this respect, good old load + execute of an .exe file (as Remy suggested) sounds like a much better option to me.
Related
In CEF4Delphi it is possible to maintain the browser session with
GlobalCEFApp.PersistSessionCookies := True;
GlobalCEFApp.Cache := 'cache_folder';
thanks to this, one can keep embeed browser logged in, for example, mail. Unfortunately, this solution saves the entire cache of the browser, including attachments etc., which makes the cache folder very large after a while. In the previous version (CEF3) was an option to manage only a component that took up very little on the disk:
CookieManager := TCefCookieManagerRef.Global(nil);
CookieManager.FlushStore(nil);
but I have not found a similar solution for CEF4, while the command
GlobalCEFApp.PersistUserPreferences := True;
GlobalCEFApp.UserDataPath := 'User_Data_folder';
does not save any information in the created folder at all.
Is there any method to keep logging only without saving the entire cache? Or maybe some philosophy which i did not figured out yet, for example deleting some specific folders with a saved cache?
Note: My version of CEF4Delphi uses CEF 86.0.21 which includes Chromium 86.0.4240.183; i'm using TChromium component.
If you are using Global Cookie manager you should also set GlobalCEFApp.PresistSessionCookies to True
CEF4Delphi also has two properties which you can use to delet od cache or cookies upon CEF application initialization. These are DeleteCache and DeleteCookies.
I'm using the CEF3 2378.1280 branch and Delphi 10.1. I'm using the following code to save sessions:
var
CookieManager: ICefCookieManager;
FromCreate:
CookiesPath := ExtractFilePath(Application.ExeName) + 'cookies';
CookieManager := TCefCookieManagerRef.Global(nil);
CookieManager.SetStoragePath(CookiesPath, true, nil);
This code work fine with Facebook and a lot of other sites. But for web.whatsapp.com it can't save the session: After restarting the program, I must do tge QR-code validation again.
How can I save a WhatsApp session?
I'm sorry I asked you to move your question here. Usually, all questions that may have something to do with CEF bindings are redirected to their respective forums and this is a pure DCEF3 question.
You don't need to specify a separate cookies directory. All you need is to set a cache directory using the 'CefCache' variable.
The CEF3 2378.1280 branch is too old and that website may not support it. Upgrade to CEF3.2623 if you still need to support Windows XP and Vista, or upgrade to CEF3.3440 if you want the latest branch.
If you decide to use CEF3.2623 you can use DCEF3 or OldCEF4Delphi.
To use the latest branch you will have to use CEF4Delphi.
How to destroy the Tchromium component dynamically created ? I'm using in a DLL , the component necessary to create and destroy it several times without deallocate the DLL, the problem is that is not releasing memory and is unable to clear the cache folder. If I use CefShutDown problems occur in time to recreate the browser again. I'm using the latest version of DCEF3 .
Create dynamically like this:
crm := TChromium.Create(Form1);
crm.SetParentComponent (Panel2);
crm.Align := alClient;
to destroy tried in several ways:
FreeAndNil(crm);
crm.free;
crm := nil;
CefShutDown;
The CefShutDown resolved in time to destroy , the problem is occurring by the time I try again recreate the component without deallocate my DLL.
Also solve another problem I'm having with the UserAgent can not change the recreation of the browser.
I appreciate any suggestions to solve my problem.
This behaviour is as designed. Issue 1237 on the Chromium issue tracker is identical to your issue. The relevant excerpt is:
CefInitialize/CefShutdown cannot be called multiple times in the same process. You can create/destroy multiple browser windows without re-initializing CEF.
You will have to refrain from calling CefShutDown.
I have some problems on files which are placed in a LAN: there is a single Delphi program (server) which should write some files, which can be only read by multiple Deplhi programs (clients).
I use these simple instructions in the server for writing (DataList is a TStrings):
Stream:=TFileStream.Create(filePath,fmOpenWrite or fmShareDenyWrite);
try
DataList.SaveToStream(Stream);
finally
Stream.Free;
end;
The clients check every 5 seconds if the file above is modified (by just checking the FileAge), and if modifications are occurred, they load the DataList in the following way:
try
Stream:=TFileStream.Create(filePath,fmOpenRead or fmShareDenyNone);
DataList.LoadFromStream(Stream);
finally
Stream.Free;
end;
Normally everything works perfectly, but sometimes it happens that the server or the client raise an exception because "the file is in use by other process".
I don't understand which is the problem: I tried many alternatives, but this can happen also with just the server and only one istance of the client running..
Any ideas?
Thanks!
By design, network file systems can't be trusted. At least, NFS (in Linux) and SMB (in Windows) have no proven lock feature: concurrent access is not safe.
You need to use a Client-Server protocol to ensure that shared data is safe. You can use TCP/IP, HTTP or any other mean.
I recommend using a true service implementation, like DataSnap, RemObjects or our Open Source mORMot.
Two Delphi programs need to load foo.dll, which contains some code that injects a client-auth certificate into a SOAP request. foo.dll resides in c:\fooapp\foo.dll and is normally loaded by c:\fooapp\foo.exe. That works fine. The other program needs the same functionality, but it resides in c:\program files\unwantedstepchild\sadapp.exe. Both aps load the DLL with this code:
FOOLib := LoadLibrary('foo.dll');
...
If FOOLib <> 0 then
begin
FOOProc := GetProcAddress(FOOLib , 'xInjectCert');
FOOProc(myHttpRequest, Data, CertName);
end;
It works great for foo.exe, as the dll is right there. sadapp.exe fails to load the library, so FOOLib is 0, and the rest never gets called. The sadapp.exe program therefore silently fails to inject the cert, and when we test against production, it the cert is missing, do the connection fails. Obviously, we should have fully-qualified the path to the DLL. Without going into a lot of details, there were aspects of the testing that masked this problem until recently, and now it's basically too late to fix in code, as that would require a full regression test, and there isn't time for that.
Since we've painted ourselves into a corner, I need to know if there are any options that I've overlooked. While we can't change the code (for this release), we CAN tweak the installer. I've found that placing c:\fooapp into the path works. As does adding a second copy of foo.dll directly into c:\program files\unwantedstepchild.
c:\fooapp\foo.exe will always be running while sadapp.exe is running, so I was hoping that Windows would find it that way, but apparently not. Is there a way to tell Windows that I really want that same DLL? Maybe a manifest or something? This is the sort of "magic bullet" that I'm looking for.
I know I can:
Modify the windows path, probably in the installer. That's ugly.
Add a second copy of the DLL, directly into the unwantedstepchild folder. Also ugly
Delay the project while we code and test a proper fix. Unacceptable.
Other?
Thanks for any guidance, especially with "Other". I understand that this issue is not necessarily specific to Delphi. Thanks!
The MSDN documentation for LoadLibrary tells you exactly where Windows will search for the DLLs. You either have to hard-code the path to the DLL, put it in the same folder as your app, or put it in one of those default search locations from the LoadLibrary docs.
This is not exactly a solution for the question asked, but it would have helped me, when I stumpled upon this question:
You can extend the search path for LoadLibrary via SetDllDirectory.
From MSDN-Doku:
The search path can be altered using the SetDllDirectory function.
This solution is recommended instead of using SetCurrentDirectory or
hard-coding the full path to the DLL.
You would have needed to add one line before your LoadLibrary call(s):
SetDllDirectory(PChar('c:\fooapp'));
Or you can simply edit the environment variable "path" and place the path to the dll in there. In this case adding ;c:\fooapp to the path should be sufficient. Since the environment changes of a parent effects a child, you can also create a loader application which adjusts the its environment variable then spawns to your application.