Closed GoogleCodeExporter closed 9 years ago
A DLL build option is coming in the near future.
Original comment by magreenb...@gmail.com
on 14 Jan 2009 at 8:08
I already made it for my own, can send you diffs.
Original comment by vrid...@gmail.com
on 15 Jan 2009 at 7:59
Diffs are always welcome. Please add them as a file attachment to this issue
:-).
Original comment by magreenb...@gmail.com
on 15 Jan 2009 at 2:33
Here they are.
Original comment by vrid...@gmail.com
on 15 Jan 2009 at 2:52
Attachments:
Please also add a line to the AUTHORS.txt file so that I can credit you
properly.
Original comment by magreenb...@gmail.com
on 15 Jan 2009 at 3:06
With VS2005 I get heap corruption in destructors of objects passed across the
DLL
boundary. This is because both libcef and cefclient are currently built using
/MTd
(Multi-Threaded Debug), which results in the DLL and the EXE having separate
heap
memory regions. I've been unable to build libcef using /MTd (Multi-Threaded
Debug
DLL) due to compile errors. If both libcef and cefclient were built using /MTd
it
would resolve the heap corruption issue because they would both be sharing the
heap
provided by the external runtime.
Problems with objects being allocated/deallocated across the DLL boundary are
primarily related to the use of standard library types. Currently, we use
std::wstring as the return value for a number of methods. Returning a
std::wstring
results in the memory being allocated in the DLL and freed in the client
application,
which causes the heap error. Similarly, if we passed the std::wstring as an
argument
by reference into the DLL the resizing (free/reallocate) would still take place
in
the DLL, again resulting in the heap error. This leaves us with three options:
1. Avoid passing or returning standard library objects across the DLL boundary
if
those objects will be modified. For instance, have the client pass in a wchar_t*
buffer instead of returning a std::wstring object.
2. Have the client application provide an allocator that would be used in the
creation or modification of any standard library objects passed across the DLL
boundary.
3. Create our own versions/extensions of the standard library types that handle
memory allocation correctly and use those instead of the standard library types.
Original comment by magreenb...@gmail.com
on 15 Jan 2009 at 5:43
> With VS2005 I get heap corruption in destructors of objects passed across the
DLL
boundary. This is because both libcef and cefclient are currently built using
/MTd
(Multi-Threaded Debug), which results in the DLL and the EXE having separate
heap
memory regions. I've been unable to build libcef using /MTd (Multi-Threaded
Debug
DLL) due to compile errors. If both libcef and cefclient were built using /MTd
it
would resolve the heap corruption issue because they would both be sharing the
heap
provided by the external runtime.
Problem is not connected to different /M flags. WebKit use FastAlloc, and this
is
incompetible with standard allocator. See USE_SYSTEM_MALLOC define and
FastAlloc.h/.cpp
Original comment by vrid...@gmail.com
on 15 Jan 2009 at 6:07
Anycase, passing string/wstring or other STL container through Dll boundaries
is a
bad idea. Now I'm looking for quick replacement for it
Original comment by vrid...@gmail.com
on 15 Jan 2009 at 6:14
I've found quick'n'dirty solution, see attached patch. Of course I don't like
it -
overriding of global new/delete operators is a bad idea, as for me. Also, using
dllexport functions for new/delete will affect performance.
Ideally, the best solution (at least, for me ;) ) will be pure C interface,
exported
from libcef.dll, probably, with C++ wrappers around it. Pure C interface will
avoid
problems like we've ran into, and also can be easy integrated with .Net/Java
and even
Visual Basic. From the other side, C++ wrappers will allow easy integrate CEF
into
existing C++ projects.
Original comment by vrid...@gmail.com
on 16 Jan 2009 at 8:30
Attachments:
My current plan is a C interface with a separate, optional, C++ wrapper. I will
probably keep the existing libcef as a static library (renamed to libcef_s), and
create a new libcef library that links against libcef_s and exports the C
interface.
Here are the highlights for the proposed C API that I'm currently working on:
1. Move all struct/enum definitions out of cef.h into a separate header.
Definitions
will follow standard C naming conventions ('_t' for typedef'd values, macros in
capitals, function names all in lower case with underscores, etc). Aliases to
camel
case will be provided for structs/enums used by the existing C++ API.
2. Provide structure definitions with a 1:1 relationship to Cef objects and that
maintain the reference counting concept:
typedef struct _cef_base_t
{
size_t size; // structure size, used for backwards/forwards version compatibility
int type; // object type, #ifdef'd values
void* ptr; // opaque implementation pointer
int (CEF_CALLBACK *add_ref)(cef_base_t* base);
int (CEF_CALLBACK *release)(cef_base_t* base);
} cef_base_t;
typedef struct _cef_browser_t
{
cef_base_t base;
bool_t (CEF_CALLBACK *can_go_back)(cef_browser_t* browser);
// And so on
} cef_browser_t;
3. All new methods will be added at the end of existing structures to maintain
binary
compatibility between versions.
4. All strings will be null-terminated wchar_t*. Strings will be returned via
wchar_t* buffers provided by the calling code.
cef_browser_t *myBrowser = ...;
size_t length;
wchar_t *buff;
// Retrieve the length of the URL, not including the NULL terminator.
myBrowser->get_url_length(&length);
// Allocate a buffer with enough space for the URL including the NULL
terminator.
buff = (wchar_t*)malloc(sizeof(wchar_t) * (length+1));
// Read the URL into the buffer. If the buffer is too short the string will
// be truncated. A NULL terminator will always be added at the end of the
string.
myBrowser->get_url(buff, length);
// Print the URL.
wprintf(L"url is %s", buff);
// Free the buffer.
free(buff);
5. Provide C-style functions for existing C++ static methods:
bool_t CEF_EXPORT cef_create_browser(cef_window_info_t* window_info, bool_t
popup,
cef_handler_t* handler, wchar_t* url)
6. Provide a static C++ library with Cef class wrappers calling the C API
exported by
libcef. The wrappers will match the C++ API exactly to allow transparent
switching
between static and dynamic builds of libcef.
Original comment by magreenb...@gmail.com
on 16 Jan 2009 at 3:44
Looks good for me.
Just some ideas:
I'd rather have a following base structure:
typedef struct _cef_base_t
{
int (CEF_CALLBACK *add_ref)(cef_base_t* base);
int (CEF_CALLBACK *release)(cef_base_t* base);
} cef_base_t;
All memory will be freed by "release" function, so we do not need to have
neither
size, nor pointer to implementation. Let's have COM or XPCOM in mind to see how
create OO-programs for pure C ;)
Also, to work with string - I think it will be better to have couple of
functions in
API like alloc_string(wchar_t*)/free_string(wchar_t*) and pass all strings
through
them. It also very close to COM BSTR implementation.
Original comment by vrid...@gmail.com
on 16 Jan 2009 at 5:14
A. I agree that we could do away with the implementation pointer by using nested
structures and type casting:
struct my_browser_t
{
cef_browser_t browser;
...
};
cef_browser_t* browser = ...;
struct my_browser_t* mybrowser = (struct my_browser_t*)browser;
However, I'm not a big fan of creating a new structure (or class) every time we
need
to add a new member function, which is the versioning system used by COM. I
would
prefer something like the WinAPI where the size member of the structure tells
us what
members it will contain. This allows us both backwards and forwards
compatibility
with the same data structures (as long as we always add new members at the end
of the
structure, and don't get too carried away with using nested structures to
simulate
inheritance). Of course, we will have to make it clear that the size member is
the
size of the nested CEF API structure as defined in the CEF header, not the size
of
the wrapping implementation structure.
On the subject of strings, the only objection I have to an API like COM BSTR is
the
level of complexity it could add for the user. But then, allocating and
managing
buffers isn't very pretty either, so I'll explore your suggestion and see where
it
takes me.
Original comment by magreenb...@gmail.com
on 16 Jan 2009 at 6:22
Yet another patch - I've added "ExecuteJavascript" method to Browser interface.
Original comment by vrid...@gmail.com
on 17 Jan 2009 at 4:07
Attachments:
The ExecuteJavascript method should accept a TargetFrame parameter so that
either the
main frame or the focused frame can be targetted.
Original comment by magreenb...@gmail.com
on 21 Jan 2009 at 4:10
I already made it, there is updated path.
I also added some handlers to catch some additional events in Handler - popup
window
show and popup window close.
By the way, may be you know - is it possible to run CEF/Chromium in my own
message
loop? In most cases having 2 message loops is a cause of problems.
Original comment by vrid...@gmail.com
on 21 Jan 2009 at 4:20
Attachments:
What kind of problems are you having?
Original comment by magreenb...@gmail.com
on 21 Jan 2009 at 4:30
Deadlocks in most cases.
CEF calls Handler methods in it's UI thread, but I need to pass it's call into
my
framework thread. I use something like SendMessage for this. In this case, CEF
thread
is locked until my component returns. If my component opens additional windows
in
this handler, these windows waits for redraw from Chromium. But as far as CEF
thread
is locked, I got a deadlock there.
Original comment by vrid...@gmail.com
on 21 Jan 2009 at 4:36
You should use PostMessage(), which is the thread-safe non-blocking form of
SendMessage(). If you need the multi-threaded communication to block then you
should
use events as demonstrated by the CefBrowserImpl::GetSource() method in
browser_impl_win.cc. We may also need to expose a version of the PostTask()
function
in the future so that CEF users can specify code for execution on the UI thread.
Original comment by magreenb...@gmail.com
on 21 Jan 2009 at 4:49
[deleted comment]
Look at Handler.HandleBeforeCreated, for example.
My code should run actual workers in another message thread (let's call it
Appframework message thread), to be thread-consistence with this framework.
From the
other side, this worker should return some decision - shell I allow popup to
appear
or not. So, I can not allow CEF message loop to run until my worker (in
Appframework
thread!) finished it's work. From the other case, if this worker creates some
windows
that requires Chromium windows redrawing, we've got a deadlock.
Original comment by vrid...@gmail.com
on 21 Jan 2009 at 5:08
Blocking the UI thread in this case probably isn't a good idea. What you can
do is
cancel the new window creation (return RV_HANDLED from HandleBeforeCreated) and
then,
after your processing is complete, call CreateBrowser() with the parameters
originally passed to HandleBeforeCreated. This might be problematic, however,
if you
have JavaScript that assumes the existence of the new window.
Original comment by magreenb...@gmail.com
on 21 Jan 2009 at 5:17
> This might be problematic, however, if you have JavaScript that assumes the
existence of the new window.
Exactly.
I'm trying to substitute MessageLoopForUI to workaround this now.
I will report you about results.
Original comment by vrid...@gmail.com
on 21 Jan 2009 at 5:29
You might also try modifying the JavaScript so that either (a) it polls for the
new
window to exist or (b) the container executes a JavaScript call after the
window is
created to continue the JavaScript execution.
Original comment by magreenb...@gmail.com
on 21 Jan 2009 at 5:39
It seems I've got some results. There is a diff file to show the main idea (not
a
final patch, of course). At least, cefclient seems to work with this issue in
the
single message loop.
Original comment by vrid...@gmail.com
on 21 Jan 2009 at 7:20
Attachments:
There is final patch for running Chromium UI in my own message loop. Looking
forward
for your comments ;)
Original comment by vrid...@gmail.com
on 22 Jan 2009 at 4:40
Attachments:
By the way, if we are removing extra message loop, we can change
Browser::CreateBrowser to allow it to return Browser instance.
This will simplify an API - it much simple for user to get ready-to-use Browser
instance from a factory method instead of waiting for it in the handler (for
some
simplest cases user will not be forced to create Handler at all).
What do you think of this idea?
Original comment by vrid...@gmail.com
on 23 Jan 2009 at 1:20
I haven't had a chance to test it yet, but your concept of running chromium UI
in the
current thread's message loop looks OK. In your modified version of cefclient,
when
do you call CefDoMessageLoopWork()?
I agree that if we remove the extra message loop we could return the CefBrowser
instance directly from CefBrowser::CreateBrowser().
If we move to a single message loop then we could actually make all of CEF
single-threaded. The code simplification gains might not be worth the loss of
multi-threaded support, though.
Original comment by magreenb...@gmail.com
on 23 Jan 2009 at 3:09
> In your modified version of cefclient, when do you call
CefDoMessageLoopWork()?
Just inside message loop:
// Main message loop
while (GetMessage(&msg, NULL, 0, 0))
{
CefDoMessageLoopWork();
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Original comment by vrid...@gmail.com
on 23 Jan 2009 at 4:17
Patch for solution with running in a single message loop
Original comment by vrid...@gmail.com
on 28 Jan 2009 at 10:03
Attachments:
What do you use the HandleBeforeWindowShow(), HandleAfterWindowShow() and
HandleBeforeWindowClose() notifications for?
Original comment by magreenb...@gmail.com
on 29 Jan 2009 at 5:53
rev 12 adds CefBrowser::ExecuteJavaScript() and rev 13 adds single-threaded
message
loop support.
Original comment by magreenb...@gmail.com
on 29 Jan 2009 at 6:54
> What do you use the HandleBeforeWindowShow(), HandleAfterWindowShow() and
HandleBeforeWindowClose() notifications for?
They are supposed to be used as a notifications for opening/showing popup
windows (IE
has similar one). But it's not a final version, I will send you updated diff
when
they will be ready (I think it will be in a day or two).
Original comment by vrid...@gmail.com
on 29 Jan 2009 at 7:03
Hi all!
i'm not a c++ programmer ( unfortunately :( ) , but i want try to use a
chromium in
my project on delphi. so at this point i need to create dynamic library with
chromium inside and minimum exported functions that can create, destroy,
navigate
(at least url in creation time ) chromium instance. all what i need - just a
windows
handle of this instance .
i look on this project - wow - it's a magic ((c) David Blein) - that is what i
need.
(thanks a lot for magreenblatt, and for all who make this project better ).
i tried to build rev 10 - it's was builded successfully, cefclient is work.
after that i try to build last (15 ) revision - there is some problems with
build (
i think that problem in a chrome revision (from compability list ) or
in my hands 8-(
Now main question - anybody can help me to make a dynamic library with
functionality like a cefclient - because when i tried to make it (
i create new empty library (another one project in chromiumembedded), declare 3
export functions to test (
extern CEFDLL_API bool CefInitialize(bool multi_threaded_message_loop);
extern CEFDLL_API void CefShutdown();
extern CEFDLL_API void CefDoMessageLoopWork();
), write include cefclient.h, cef.h
but project did'nt builded - cef.h not found :(
help me please with writing this simple dll or finish this issue - it is much
better :)
with best regards to all those involved in this project,
Alexander
Original comment by azy...@gmail.com
on 26 Feb 2009 at 9:14
Rev 16 adds DLL build support. Feedback and testing is welcome :-).
Original comment by magreenb...@gmail.com
on 5 Mar 2009 at 1:12
The project does not open with Chromium revision trunk@9652 declared in
CHROMIUM_BUILD_COMPATIBILITY.txt
Original comment by azy...@gmail.com
on 5 Mar 2009 at 12:08
What project does not open? What error message do you get?
Original comment by magreenb...@gmail.com
on 5 Mar 2009 at 2:30
Cannot open include file: 'ScriptState.h' and 'ScriptInstance.h'
Original comment by peng.che...@gmail.com
on 5 Mar 2009 at 4:51
You were probably not at the correct revision of chromium as set up by gclient
sync.
In any case, update to rev 17, which will fix your include problem.
Original comment by magreenb...@gmail.com
on 5 Mar 2009 at 5:17
Release build is broken in rev 19, I attached a patch to fix it.
Original comment by vrid...@gmail.com
on 8 Mar 2009 at 10:32
Attachments:
Sorry, previous patch is not complete
There is a correct one
Original comment by vrid...@gmail.com
on 8 Mar 2009 at 10:34
Attachments:
Thanks for the patch. Release build compile error fixed in rev 20.
Original comment by magreenb...@gmail.com
on 9 Mar 2009 at 1:23
Original comment by magreenb...@gmail.com
on 17 Sep 2009 at 6:41
Original issue reported on code.google.com by
vrid...@gmail.com
on 10 Jan 2009 at 4:33