Making Gecko a CLR friendly component using MSVS-The Managed Extensions for C++ git-svn-id: svn://10.0.0.236/trunk@142519 18797224-902f-48f8-a5cc-f745e15eee43
274 lines
10 KiB
HTML
274 lines
10 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="content-type"
|
|
content="text/html; charset=ISO-8859-1">
|
|
<title>Convert Gecko from unmanged to managed code in .Net</title>
|
|
</head>
|
|
<body>
|
|
<h1 style="margin-left: 40px;">Convert Gecko APIs from unmanaged to
|
|
managed using </h1>
|
|
<h1 style="margin-left: 40px;">Managed Extensions for Microsoft Visual
|
|
Studio C++ .Net<br>
|
|
</h1>
|
|
<br>
|
|
<br>
|
|
<h2>Intended Audience:</h2>
|
|
This paper is intended for a C++ programmer who would like to know how
|
|
to convert the Gecko from unmanaged C++ to managed C++ in Microsoft
|
|
.Net, CLR environment. Author assumes the reader is familiar with
|
|
Gecko XPCOM and MS C++ .Net with Managed Extensions.<br>
|
|
<br>
|
|
<h2>Background:</h2>
|
|
Why do we go all this trouble? When we have Gecko as ActiveX
|
|
control, then why don't we use the Runtime-Callable Wrapper (RCW) and
|
|
COM-Callable Wrapper (CCW)? <br>
|
|
<br>
|
|
<h2 class="dtH1">Three Ways to Use Code</h2>
|
|
<p>There are three basic ways to use existing code: </p>
|
|
<ol type="1">
|
|
<li>You can use the built-in .NET runtime interop facilities to talk
|
|
directly to the existing code.</li>
|
|
<li>You can wrap the code using the managed extensions to C++.</li>
|
|
<li>You can rewrite the code in a .NET language.</li>
|
|
</ol>
|
|
<br>
|
|
<h2>Terminology:</h2>
|
|
Following terms are used throught out this document and it is important
|
|
to understand what each term means. <br>
|
|
<ul>
|
|
<li style="font-weight: bold;">CLR</li>
|
|
<li style="font-weight: bold;">Runtime-Callable Wrapper (RCW)</li>
|
|
<li style="font-weight: bold;">COM-Callable Wrapper (CCW)</li>
|
|
<li style="font-weight: bold;">Boxing</li>
|
|
</ul>
|
|
<div style="margin-left: 80px;">Boxing is a technique to convert a
|
|
value type to a __gc object by using the __box<br>
|
|
<div style="margin-left: 40px;">Int32 i = 42;<br>
|
|
__box Int32* b = __box(i);<br>
|
|
</div>
|
|
</div>
|
|
<ul>
|
|
<li style="font-weight: bold;">UnBoxing</li>
|
|
</ul>
|
|
<div style="margin-left: 80px;">UnBoxing (dereferencing) is a technique
|
|
to convert a boxed object to value type by casting.<br>
|
|
<div style="margin-left: 40px;">Color red;<br>
|
|
Object* obj = Enum::Parse(__typeof(Color), S"red");<br>
|
|
red = *static_cast<__box Color*>(obj);<br>
|
|
</div>
|
|
</div>
|
|
<br>
|
|
<ul>
|
|
<li style="font-weight: bold;">Managed Objects</li>
|
|
</ul>
|
|
<div style="margin-left: 80px;">Managed Object is an instance of a
|
|
class which is created in the heap and managed by the garbage collector
|
|
by using the <span style="font-style: italic;">__gc</span>
|
|
modifier. <br>
|
|
<div style="margin-left: 40px;"><span style="font-style: italic;">__gc</span>
|
|
class Point<br>
|
|
{<br>
|
|
</div>
|
|
<div style="margin-left: 80px;">public:<br>
|
|
</div>
|
|
<div style="margin-left: 120px;"> int x;<br>
|
|
int y;<br>
|
|
</div>
|
|
<div style="margin-left: 40px;"> };<br>
|
|
</div>
|
|
</div>
|
|
<ul style="font-weight: bold;">
|
|
<li>Value Types</li>
|
|
</ul>
|
|
<div style="margin-left: 80px;">Value Types ar typically small, short
|
|
lived objects and they are usually created on the stack. In managed C++,
|
|
the value types are defined by using <span style="font-style: italic;">__value</span>
|
|
modifier. <br>
|
|
<div style="margin-left: 40px;"><span style="font-style: italic;">__value</span>
|
|
class Point<br>
|
|
{<br>
|
|
</div>
|
|
<div style="margin-left: 80px;">public:<br>
|
|
</div>
|
|
<div style="margin-left: 120px;"> int x;<br>
|
|
int y;<br>
|
|
</div>
|
|
<div style="margin-left: 40px;"> };<br>
|
|
</div>
|
|
</div>
|
|
<ul>
|
|
<li><span style="font-weight: bold;">Assembly</span><br>
|
|
</li>
|
|
</ul>
|
|
<div style="margin-left: 80px;">Assembly is a building block of the
|
|
.Net Framework. It is the fundamental unit of deployment, version
|
|
control, reuse, activation, scoping, and security permissions. It
|
|
provides the Common Language Runtime (CLR) with the information it needs
|
|
to be aware of type implementations. It is a collection of types
|
|
and resources that are built to work together and form a logical unit of
|
|
functionality. <br>
|
|
</div>
|
|
<ul style="font-weight: bold;">
|
|
<li>Global Assembly Cache</li>
|
|
</ul>
|
|
<div style="margin-left: 80px;">Global Assembly Cache is a machine wide
|
|
code cache that is installed whereever the CLR is installed. In
|
|
most cases, if you intend to share an assembly with multiple
|
|
applications, you should deploy it into the global assembly cache.<br>
|
|
</div>
|
|
<ul>
|
|
<li><span style="font-weight: bold;">Managed code vs Unmanaged code</span></li>
|
|
</ul>
|
|
<div style="margin-left: 80px;"><span style="font-style: italic;">Manged
|
|
code</span> requires the execution environment of the CLR.
|
|
Compilers emit managed code as MSIL, the intermidate language. The
|
|
reason for the name is that code is managed by the CLR and objects are
|
|
allocated from heaps managed by the CLR.<br>
|
|
<span style="font-style: italic;">Unmanaged code</span> does not use nor
|
|
require the execution environment of the Common Language Runtime
|
|
(CLR). Unmanaged code is outside the reach of the CLR's security
|
|
system, garbage collector and other services.<br>
|
|
</div>
|
|
<h2>Necessary Steps:</h2>
|
|
<ul>
|
|
</ul>
|
|
<ol>
|
|
<li>Create a wrapper Assembly library using MS Visual C++ .Net with
|
|
Managed Extensions</li>
|
|
<li><br>
|
|
</li>
|
|
</ol>
|
|
<ul>
|
|
<li>Convert IDL to a type library by using MIDL.exe or MKTYPLIB.exe</li>
|
|
<ul>
|
|
<li>IDL file-> MIDL.EXE -> TYPELIB file-> TLBIMP.EXE ->
|
|
Interop Assembly file (-> ILDASM.EXE -> IL file)<br>
|
|
</li>
|
|
</ul>
|
|
<li>Create a Multifile Library Assemblies</li>
|
|
<ul>
|
|
<li>set Assembly Attributes</li>
|
|
<li>create Shared (Strong-Named) Assembly<br>
|
|
</li>
|
|
<li>cl /CLR:noAssembly /c myLibrary1.cpp</li>
|
|
<li>link -dll /noassembly /node:libcpmt.lib /out:myCodeLibrary1.dll
|
|
myLibrary1.obj</li>
|
|
<li>cl /CLR:noAssembly /c myLibrary2.cpp</li>
|
|
<li>link -dll /noassembly /node:libcpmt.lib /out:myCodeLibrary2.dll
|
|
myLibrary2.obj</li>
|
|
<li>al /out:myAssembly.dll /t:lib myCodeLibrary1.dll
|
|
myCodeLibrary2.dll </li>
|
|
</ul>
|
|
<li>Add to Global Assembly Cache</li>
|
|
<ul>
|
|
<li>gacutil -i myAssembly.dll</li>
|
|
</ul>
|
|
<li>Write and test a sample code in C#<br>
|
|
</li>
|
|
</ul>
|
|
<br>
|
|
<h2>Gecko APIs</h2>
|
|
<ul>
|
|
<li>nsresult NS_InitEmbedding(nsILocalFile *aMozBinDirectory,
|
|
nsIDirectoryServiceProvider *aAppFileLocProvider);<br>
|
|
</li>
|
|
<li>nsresult NS_HandleEmbeddingEvent(nsEmbedNativeEvent &aEvent,
|
|
PRBool &aWasHandled);<br>
|
|
</li>
|
|
<li>nsresult NS_TermEmbedding();</li>
|
|
</ul>
|
|
<br>
|
|
<h2>Coding Techniques:</h2>
|
|
<ul>
|
|
<li>
|
|
<h3>Using managed object in unmanaged code</h3>
|
|
</li>
|
|
</ul>
|
|
<div style="margin-left: 40px;">Managed pointers are managed by the
|
|
garbage collector so that when copies are made, the gc knows that
|
|
references are created. When a pointer is passed to native code,
|
|
the gc cannot track its usage and so cannot determine any change in
|
|
object reference. Furthermore, if a garbage collection
|
|
occures, the object can be moved in memory, so the gc changes all
|
|
managed pointers so that they point to the new location. Because
|
|
the gc doesn't have access to the pointers passed to native code
|
|
(unmanaged code), potentially a pointer used in native code could
|
|
suddenly become invalid. Use a pinned pointer which tells gc not
|
|
to move the memory.<br>
|
|
<div style="margin-left: 80px;">
|
|
<table cellpadding="2" cellspacing="2" border="1"
|
|
style="text-align: left; width: 100%;">
|
|
<tbody>
|
|
<tr>
|
|
<td style="vertical-align: top;">//Using pinning<br>
|
|
#progma unmanaged<br>
|
|
void print(int *p)<br>
|
|
{<br>
|
|
printf("%ld\n", *p);<br>
|
|
}<br>
|
|
<br>
|
|
#progma managed<br>
|
|
_gc struct Test {<br>
|
|
int i;<br>
|
|
};<br>
|
|
<br>
|
|
void main()<br>
|
|
{<br>
|
|
Test * t = new Test;<br>
|
|
int __pin* p = &t->i;<br>
|
|
print(p);<br>
|
|
}<br>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div style="margin-left: 40px;"><br>
|
|
</div>
|
|
<ul>
|
|
<li>
|
|
<h3>Using unmanaged object in managed code</h3>
|
|
</li>
|
|
</ul>
|
|
<div style="margin-left: 120px;">
|
|
<table cellpadding="2" cellspacing="2" border="1"
|
|
style="text-align: left; width: 100%;">
|
|
<tbody>
|
|
<tr>
|
|
<td style="vertical-align: top;"><span class="clsCap">//Using
|
|
GCHandle</span> <br>
|
|
<pre>#using <mscorlib.dll><br><br>using namespace System;<br>using namespace System::Runtime::InteropServices;<br><br>#pragma managed<br>class AppDomainWrapper<br>{<br>private:<br> int m_handle;<br>public:<br> AppDomainWrapper() {<br> AppDomain* d = AppDomain::Current;<br> m_handle = (GCHandle::op_Explicit(GCHandle::Alloc(d))).ToInt32();<br> }<br> ~AppDomainWrapper() {<br> (GCHandle::op_Explicit(m_handle)).Free();<br> }<br> // more functions here...<br> void PrintBaseDir() {<br> AppDomain* domain = __try_cast<AppDomain*>(<br> (GCHandle::op_Explicit(m_handle)).Target);<br> Console::WriteLine ( S"AppDomain Base Directory: {0}",<br> domain->BaseDirectory );<br> }<br>};<br><br>#pragma unmanaged<br>int main() {<br> AppDomainWrapper w; <br> w.PrintBaseDir();<br> return 0; <br>}</pre>
|
|
</td>
|
|
<td style="vertical-align: top;"><span class="clsCap">//Using
|
|
gcroot</span> <br>
|
|
<pre>#using <mscorlib.dll><br>#include <gcroot.h><br><br>using namespace System;<br>using namespace System::Runtime::InteropServices;<br><br>#pragma managed<br>class AppDomainWrapper<br>{<br>private:<br> gcroot<AppDomain*> m_domain;<br>public:<br> AppDomainWrapper() {<br> m_domain = AppDomain::CurrentDomain;<br> }<br> ~AppDomainWrapper() {<br> }<br> // more functions here...<br> void PrintBaseDir() {<br> Console::WriteLine ( S"AppDomain Base Directory: {0}",<br> m_domain->BaseDirectory );<br> }<br>};<br><br>#pragma unmanaged<br>int main() {<br> AppDomainWrapper w; <br> w.PrintBaseDir();<br> return 0; <br><br><br><br>}</pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<span class="clsFigure"></span><span class="clsCap"></span> </div>
|
|
<h2>Useful Tools:</h2>
|
|
<ul>
|
|
<li>Viewing Assembly Contents</li>
|
|
<ul>
|
|
<li>MSIL Disassembler (ildasm.exe)<br>
|
|
</li>
|
|
</ul>
|
|
</ul>
|
|
<ul>
|
|
<li>TLBIMP.exe</li>
|
|
<li>TLBEXP.exe</li>
|
|
<li>REGASM.exe</li>
|
|
<li>AXIMP.exe</li>
|
|
<li>REGSVCS.exe<br>
|
|
</li>
|
|
</ul>
|
|
<h2>History:</h2>
|
|
Draft 0.1 : April 9 2003 Roy Yokoyama<br>
|
|
<br>
|
|
<br>
|
|
</body>
|
|
</html>
|