chromiumembedded / cef

Chromium Embedded Framework (CEF). A simple framework for embedding Chromium-based browsers in other applications.
https://bitbucket.org/chromiumembedded/cef/
Other
3.31k stars 463 forks source link

Need to build as Dll library. #25

Closed magreenblatt closed 15 years ago

magreenblatt commented 15 years ago

Original report by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Original issue 1 created by vridosh on 2009-01-10T16:33:14.000Z:

Linking with such huge static library lasts for ages. Linking with tiny
lib, provided by Dll should speed up client builds a lot.

magreenblatt commented 15 years ago

Comment 1. originally posted by magreenblatt on 2009-01-14T20:08:53.000Z:

A DLL build option is coming in the near future.

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 2. originally posted by vridosh on 2009-01-15T07:59:42.000Z:

I already made it for my own, can send you diffs.

magreenblatt commented 15 years ago

Comment 3. originally posted by magreenblatt on 2009-01-15T14:33:56.000Z:

Diffs are always welcome. Please add them as a file attachment to this issue :-).

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 4. originally posted by vridosh on 2009-01-15T14:52:08.000Z:

Here they are.

magreenblatt commented 15 years ago

Comment 5. originally posted by magreenblatt on 2009-01-15T15:06:03.000Z:

Please also add a line to the AUTHORS.txt file so that I can credit you properly.

magreenblatt commented 15 years ago

Comment 6. originally posted by magreenblatt on 2009-01-15T17:43:27.000Z:

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.
magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 7. originally posted by vridosh on 2009-01-15T18:07:54.000Z:

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

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 8. originally posted by vridosh on 2009-01-15T18:14:49.000Z:

Anycase, passing string/wstring or other STL container through Dll boundaries is a
bad idea. Now I'm looking for quick replacement for it

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 9. originally posted by vridosh on 2009-01-16T08:30:25.000Z:

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.

magreenblatt commented 15 years ago

Comment 10. originally posted by magreenblatt on 2009-01-16T15:44:22.000Z:

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;

  1. All new methods will be added at the end of existing structures to maintain binary
    compatibility between versions.

  2. 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);

  1. 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)

  1. 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.
magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 11. originally posted by vridosh on 2009-01-16T17:14:22.000Z:

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.

magreenblatt commented 15 years ago

Comment 12. originally posted by magreenblatt on 2009-01-16T18:22:12.000Z:

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.

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 13. originally posted by vridosh on 2009-01-17T16:07:25.000Z:

Yet another patch - I've added "ExecuteJavascript" method to Browser interface.

magreenblatt commented 15 years ago

Comment 14. originally posted by magreenblatt on 2009-01-21T16:10:54.000Z:

The ExecuteJavascript method should accept a TargetFrame parameter so that either the
main frame or the focused frame can be targetted.

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 15. originally posted by vridosh on 2009-01-21T16:20:59.000Z:

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.

magreenblatt commented 15 years ago

Comment 16. originally posted by magreenblatt on 2009-01-21T16:30:41.000Z:

What kind of problems are you having?

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 17. originally posted by vridosh on 2009-01-21T16:36:52.000Z:

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.

magreenblatt commented 15 years ago

Comment 18. originally posted by magreenblatt on 2009-01-21T16:49:22.000Z:

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.

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 20. originally posted by vridosh on 2009-01-21T17:08:06.000Z:

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.

magreenblatt commented 15 years ago

Comment 21. originally posted by magreenblatt on 2009-01-21T17:17:25.000Z:

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.

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 22. originally posted by vridosh on 2009-01-21T17:29:21.000Z:

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.

magreenblatt commented 15 years ago

Comment 23. originally posted by magreenblatt on 2009-01-21T17:39:25.000Z:

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.

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 24. originally posted by vridosh on 2009-01-21T19:20:29.000Z:

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.

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 25. originally posted by vridosh on 2009-01-22T16:40:52.000Z:

There is final patch for running Chromium UI in my own message loop. Looking forward
for your comments ;)

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 26. originally posted by vridosh on 2009-01-23T13:20:50.000Z:

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?

magreenblatt commented 15 years ago

Comment 27. originally posted by magreenblatt on 2009-01-23T15:09:34.000Z:

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.

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 28. originally posted by vridosh on 2009-01-23T16:17:00.000Z:

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);  
    }  
}
magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 29. originally posted by vridosh on 2009-01-28T10:03:31.000Z:

Patch for solution with running in a single message loop

magreenblatt commented 15 years ago

Comment 30. originally posted by magreenblatt on 2009-01-29T17:53:32.000Z:

What do you use the HandleBeforeWindowShow(), HandleAfterWindowShow() and
HandleBeforeWindowClose() notifications for?

magreenblatt commented 15 years ago

Comment 31. originally posted by magreenblatt on 2009-01-29T18:54:34.000Z:

rev 12 adds CefBrowser::ExecuteJavaScript() and rev 13 adds single-threaded message
loop support.

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 32. originally posted by vridosh on 2009-01-29T19:03:50.000Z:

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).

magreenblatt commented 15 years ago

Original comment by Alexander Zyrin (Bitbucket: A.Zyrin).


Comment 33. originally posted by azyrin on 2009-02-26T09:14:27.000Z:

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

magreenblatt commented 15 years ago

Comment 34. originally posted by magreenblatt on 2009-03-05T01:12:01.000Z:

Rev 16 adds DLL build support. Feedback and testing is welcome :-).

magreenblatt commented 15 years ago

Original comment by Alexander Zyrin (Bitbucket: A.Zyrin).


Comment 35. originally posted by azyrin on 2009-03-05T12:08:03.000Z:

The project does not open with Chromium revision trunk@ 9652 declared in
CHROMIUM_BUILD_COMPATIBILITY.txt

magreenblatt commented 15 years ago

Comment 36. originally posted by magreenblatt on 2009-03-05T14:30:42.000Z:

What project does not open? What error message do you get?

magreenblatt commented 15 years ago

Original comment by Anonymous.


Comment 37. originally posted by peng.chengyuan on 2009-03-05T16:51:56.000Z:

Cannot open include file: 'ScriptState.h' and 'ScriptInstance.h'

magreenblatt commented 15 years ago

Comment 38. originally posted by magreenblatt on 2009-03-05T17:17:11.000Z:

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.

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 39. originally posted by vridosh on 2009-03-08T10:32:04.000Z:

Release build is broken in rev 19, I attached a patch to fix it.

magreenblatt commented 15 years ago

Original comment by Vadim Ridosh (Bitbucket: Vadim Ridosh).


Comment 40. originally posted by vridosh on 2009-03-08T10:34:31.000Z:

Sorry, previous patch is not complete
There is a correct one

magreenblatt commented 15 years ago

Comment 41. originally posted by magreenblatt on 2009-03-09T13:23:43.000Z:

Thanks for the patch. Release build compile error fixed in rev 20.

magreenblatt commented 15 years ago

Comment 42. originally posted by magreenblatt on 2009-09-17T18:41:13.000Z:

magreenblatt commented 15 years ago

Original changes by Vadim Ridosh (Bitbucket: Vadim Ridosh).


magreenblatt commented 15 years ago

Original changes by Vadim Ridosh (Bitbucket: Vadim Ridosh).


magreenblatt commented 15 years ago

Original changes by Vadim Ridosh (Bitbucket: Vadim Ridosh).


magreenblatt commented 15 years ago

Original changes by Vadim Ridosh (Bitbucket: Vadim Ridosh).


magreenblatt commented 15 years ago

Original changes by Vadim Ridosh (Bitbucket: Vadim Ridosh).


magreenblatt commented 15 years ago

Original changes by Vadim Ridosh (Bitbucket: Vadim Ridosh).


magreenblatt commented 15 years ago

Original changes by Vadim Ridosh (Bitbucket: Vadim Ridosh).


magreenblatt commented 15 years ago

Original changes by Vadim Ridosh (Bitbucket: Vadim Ridosh).


magreenblatt commented 15 years ago

Original changes by Vadim Ridosh (Bitbucket: Vadim Ridosh).