I have a problem with the web browser memory leak - which I've found here:
How can I hide WebBrowser till the website complete the loading / download process?
The solution is to use browser.DefaultInterface.Document instead of browser.Document.
I was using this:
DelphiInterface<IHTMLDocument2> diDoc = browser->Document;
But I am using TCppWebBrowser and it only has browser->DefaultDispatch doesn't have DefaultInterface like TWebBrowser which I assume is the same thing but I don't know how to query TCppWebBrowser for IHTMLDocument2 to avoid the memory leak, until I fully switch to newer version of RAD Studio where the memory leak has been fixed (Sydney, currently on 2010).
I tried this:
DelphiInterface<IHTMLDocument2> diDoc;
browser->DefaultDispatch->QueryInterface(IID_IHTMLDocument2, &diDoc);
But that doesn't seem to work.
This works... but...
DelphiInterface<IHTMLDocument2> diDoc = browser->DefaultDispatch;
But the resulting diDoc is NULL. (it is not NULL for browser->Document which is also _di_IDispatch)
I think I solved this myself. Instead of:
DelphiInterface<IHTMLDocument2> diDoc =
browser->Document;
I simply used:
#include <SHDocVw.hpp> // required for Shdocvw::IWebBrowser2
#include "SHDocVw_OCX.h" // TCppWebBrowser
DelphiInterface<IHTMLDocument2> diDoc =
DelphiInterface<Shdocvw::IWebBrowser2>(browser->DefaultDispatch)->Document;
This also seems to work:
DelphiInterface<IHTMLDocument2> diDoc =
DelphiInterface<Shdocvw::IWebBrowser2>(browser->Application)->Document;
Alternatively:
DelphiInterface<IHTMLDocument2> diDoc = ((_di_IDispatch)browser->DefaultDispatch)->Document;
DelphiInterface<IHTMLDocument2> diDoc = ((_di_IDispatch)browser->Application)->Document;
The memory leak seems to be addressed with this just like in case of the Delphi equivalent linked in the answer above.
Related
Assuming a scenario where DX12 is being hooked for overlay rendering it looks like the best function to hook is the IDXGISwapChain::Present the same way it was done for DX11. Having this function hooked the swap chain is available and from that the device can be retrieved to create resources. Given those resources it’s possible to record rendering commands too. The problem arises when we are trying to execute the rendering commands as there is no option to retrieve the associated command queue from the swap chain so there is nothing like this:
CComPtr<ID3D12Device> pD3D12Device;
if (pSwapChain->GetDevice(__uuidof(ID3D12Device), (void**)(&pD3D12Device)) == S_OK)
{
pD3D12Device->GetCommandQueueForSwapChain( swapChain )->ExecuteCommandLists(…);
}
The other option would be creating a new command queue to execute on, like this:
CComPtr<ID3D12Device> pD3D12Device;
if (pSwapChain->GetDevice(__uuidof(ID3D12Device), (void**)(&pD3D12Device)) == S_OK)
{
D3D12_COMMAND_QUEUE_DESC queue_desc = {};
queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
HRESULT commandQueueRes = _device->CreateCommandQueue( &queue_desc, IID_PPV_ARGS( &_commandQueue ) );
_commandQueue->ExecuteCommandLists( ... );
}
This results in an error and subsequent device removal. See the error message below.
D3D12 ERROR: ID3D12CommandQueue::ExecuteCommandLists: A command list, which writes to a swap chain back buffer, may only be executed on the command queue associated with that buffer. [ STATE_SETTING ERROR #907: EXECUTECOMMANDLISTS_WRONGSWAPCHAINBUFFERREFERENCE]
The problem is not resolved even if the ID3D12CommandQueue::ExecuteCommandLists is hooked as well because there is no way to retrieve the associated swap chain from the command queue either.
So my question is what is the recommended way to deal with this problem in a scenario where the swap chain creation happens before the hooking could possibly happen?
In case anyone is looking for the answer here's what I found out.
There is no official way to do this, for overlay rendering the recommended way is to use DirectComposition but this has performance consequences which is not very nice for game overlays.
Investigating the memory a bit there is a possible solution to get the CommandQueue from the swap chain with something like this:
#ifdef _M_X64
size_t* pOffset = (size_t*)((BYTE*)swapChain + 216);
#else
size_t* pOffset = (size_t*)((BYTE*)swapChain + 132);
#endif
*(&_commandQueue) = reinterpret_cast<ID3D12CommandQueue*>(*pOffset);
Obviously this solution is not recommended but it might be useful if someone just want's to do some debugging.
My final solution is to hook into a function that uses the CommandQueue (I use ExecuteCommandLists) and get the pointer there and use it later to render the overlay. It's not completely satisfying but it works as long as there are no multiple swap chains.
final html.IFrameElement iframe = rootDemoElement.querySelector("iframe");
final int contentHeight = <???>.scrollHeight;
this works in JS:
var contentHeight = iframe.contentDocument.documentElement.scrollHeight;
contentDocument is not available in Dart.
Is it really possible that contentDocument is missing in Dart?
Here is my solution:
var jsIFrame = new JsObject.fromBrowserObject(iframe);
var contentHeight = jsIFrame["contentDocument"]["documentElement"]["scrollHeight"];
As far as I know there was an attempt to make Dart in the browser more secure than JavaScript and this led to a model where cross-window communication was limited (to postMessage). I assume an Iframe suffers from the same limitations. There was a comment on an issue that they want to leave this strategy because this is usually circumnavigated by using dart-js-interop anyway.
I think the main culprit is that you get a _DOMWindowCrossFrame instead of a Window instance.
See
http://dartbug.com/17936#c2
probably also related
http://dartbub.com/20146
http://dartbug.com/20143
http://dartbug.com/20173
http://dartbug.com/21219
http://dartbug.com/20216
http://dartbug.com/19610
http://dartbug.com/16814
http://dartbug.com/12788
http://dartbug.com/2312
Salve! When I try Mozilla's Validator on my addon, it get the following error related to my treatment of clipboard usage:
nsITransferable has been changed in Gecko 16.
Warning: The nsITransferable interface has changed to better support
Private Browsing Mode. After instantiating the object, you should call
the init function on it before any other functions are called.
See https://developer.mozilla.org/en-US/docs/Using_the_Clipboard for more
information.
var trans = Components.classes["#mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
if ('init' in trans){ trans.init(null);};
I can't understand this.
Here is my code - I am clearly calling trans.init:
var clip = Components.classes["#mozilla.org/widget/clipboard;1"].getService(Components.interfaces.nsIClipboard);
if (!clip) return "";
var trans = Components.classes["#mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
if ('init' in trans){ trans.init(null);}; //<--IT DOESN'T LIKE THIS
if (!trans) return false;
trans.addDataFlavor("text/unicode");
I've also tried the Transferable function from Mozilla's example here, but get the same non-validation report.
One of the Mozilla AMO editors told me to write exactly this, and it still doesn't validate.
I've also tried, simply:
var trans = Components.classes["#mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
trans.init(null); //<---LOOK HERE
if (!trans) return false;
trans.addDataFlavor("text/unicode");
The Validator does not report any errors - just this warning. Everything works properly. Mozilla updated their Gecko engine, and they want devlopers to match up to the new standard.
In my usage, we want to be able to use the contents of the clipboard that was probably gotten from outside the application, too, so we do want to call the init function with null instead of window.
Any advice would be wonderful!
trans.init(null) is valid in some circumstances, such as yours. It can also cause privacy leaks if used in the wrong circumstances, so the validator flags all uses of it as potentially requiring changing. Therefore, it is a warning that you can ignore in this case.
I have a strange behavior with the manual binding:
Ember.bind(App, "value", "App.wife.value");
The bound value isn't updated when the source is updated:
App.wife.set('value', 2); // App.value isn't updated
But when the bound value is updated, the source is updated:
App.set('value', 4); // App.wife.value is updated
http://jsfiddle.net/wooandoo/ZN9Sg/1/
What's wrong?
Hum, it seems like Ember.bind() indeed does not work with global path.
Using Ember.bind(App, 'value', 'wife.value') seems to work. Perhaps there is a bug.
I have downloaded opensource delphi twain component (TDelphiTwain).
The interesting thing is, that when placed and saved on the form it creates bad dfm entry for itself.
object DelphiTwain: TDelphiTwain
OnSourceDisable = DelphiTwainSourceDisable
OnSourceSetupFileXfer = DelphiTwainSourceSetupFileXfer
TransferMode = ttmMemory
SourceCount = 0
Info.MajorVersion = 1
Info.MinorVersion = 0
Info.Language = tlDanish
Info.CountryCode = 1
Info.Groups = [tgControl, tgImage, tgAudio, MinorVersion]
Info.VersionInfo = 'Application name'
Info.Manufacturer = 'Application manufacturer'
Info.ProductFamily = 'App product family'
Info.ProductName = 'App product name'
LibraryLoaded = False
SourceManagerLoaded = False
Left = 520
Top = 136
end
The problem is with the line:
Info.Groups = [tgControl, tgImage, tgAudio, MinorVersion]
There are only three possible elements:
tgControl, tgImage and tgAudio
It adds MinorVersion everytime I Save the form.
When the app is run I get the error that there is invalid property for Info.Groups.
When i rmeove the bad part manually and without leaving dfm file the app starts ok.
I looked in the internet and there was one inquire regarding these strange issue, unfortunately it hasn't been resolved.
I think that there is some sort of memory corruption. In the post in teh internet, strange signs were displayed ...
Has anyone worked with that component or could give me some hint how this could be fixed?
The error seems to be in TTwainIdentity.GetGroups where result is not initialized. You can try to change the code by replacing
Include(Result, tgControl);
with
Result := [tgControl];
You have to recompile the package to make this change work inside the IDE.
I don't know the component, but I think the problem lies in the TTwainIdentity.GetGroups method. It starts like this:
begin
Include(Result, tgControl);
This means that it assumes that Result is initialized to an empty set. However, Result may contain garbage, and not necessarily an empty set. Change this method to look like this:
function TTwainIdentity.GetGroups(): TTwainGroups;
{Convert from Structure.SupportedGroups to TTwainGroups}
begin
Result := [tgControl];
if DG_IMAGE AND Structure.SupportedGroups <> 0 then
Include(Result, tgImage);
if DG_AUDIO AND Structure.SupportedGroups <> 0 then
Include(Result, tgAudio);
end;
Some result types will not throw a compiler warning about not being initialized, but that doesn't mean they are empty. Same goes, for instance, for strings.
See also: http://qc.embarcadero.com/wc/qcmain.aspx?d=894
But still, it is odd that this happens. Apparently, Delphi tries to find the name of the given item in the set and accidentally finds the name of another property. It seems to me that quite some checks in writing the dfm are missing if this happens. :)