<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=US-ASCII">
<META NAME="Generator" CONTENT="MS Exchange Server version 5.5.2653.12">
<TITLE>AW: [C++-sig] Wrapping opaque pointers returned from API functions</TITLE>
</HEAD>
<BODY>

<P><FONT SIZE=2>Hi Dave,</FONT>
</P>

<P><FONT SIZE=2>I knew it was something simple (although not entirely obvious :-))</FONT>
</P>

<P><FONT SIZE=2>Thanks a lot,</FONT>
</P>

<P><FONT SIZE=2>Gottfried</FONT>
</P>

<P><FONT SIZE=2>&gt; -----Ursprungliche Nachricht-----</FONT>
<BR><FONT SIZE=2>&gt; Von: David Abrahams [<A HREF="mailto:dave@boost-consulting.com">mailto:dave@boost-consulting.com</A>]</FONT>
<BR><FONT SIZE=2>&gt; Gesendet: Donnerstag, 9. Januar 2003 18:59</FONT>
<BR><FONT SIZE=2>&gt; An: c++-sig@python.org</FONT>
<BR><FONT SIZE=2>&gt; Betreff: Re: [C++-sig] Wrapping opaque pointers returned from API</FONT>
<BR><FONT SIZE=2>&gt; functions</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; Gottfried.Ganssauge@HAUFE.DE writes:</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; &gt; I am trying to wrap an API like the following:</FONT>
<BR><FONT SIZE=2>&gt; &gt; &nbsp;&nbsp;&nbsp; typedef struct workspace_ *workspace;</FONT>
<BR><FONT SIZE=2>&gt; &gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt; &nbsp;&nbsp;&nbsp; workspace osr_init (const char *) { return 0; }</FONT>
<BR><FONT SIZE=2>&gt; &gt; &nbsp;&nbsp;&nbsp; void osr_exit (workspace ws) { std::cerr &lt;&lt; ws &lt;&lt; std::endl; }</FONT>
<BR><FONT SIZE=2>&gt; &gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt; My first attempt at wrapping that API was</FONT>
<BR><FONT SIZE=2>&gt; &gt; &nbsp;&nbsp;&nbsp; BOOST_PYTHON_MODULE(_pyOSR)</FONT>
<BR><FONT SIZE=2>&gt; &gt; &nbsp;&nbsp;&nbsp; {</FONT>
<BR><FONT SIZE=2>&gt; &gt; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def (&quot;osr_init&quot;, &amp;::osr_init, </FONT>
<BR><FONT SIZE=2>&gt; return_value_policy&lt;return_by_value&gt;());</FONT>
<BR><FONT SIZE=2>&gt; &gt; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def (&quot;osr_exit&quot;, &amp;::osr_exit);</FONT>
<BR><FONT SIZE=2>&gt; &gt; &nbsp;&nbsp;&nbsp; }</FONT>
<BR><FONT SIZE=2>&gt; &gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt; That compiled fine, but (of course) failed miserably when </FONT>
<BR><FONT SIZE=2>&gt; run with the</FONT>
<BR><FONT SIZE=2>&gt; &gt; following test script:</FONT>
<BR><FONT SIZE=2>&gt; &gt; &nbsp;&nbsp;&nbsp; import _pyOSR</FONT>
<BR><FONT SIZE=2>&gt; &gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt; &nbsp;&nbsp;&nbsp; ws = _pyOSR.osr_init(&quot;.&quot;)</FONT>
<BR><FONT SIZE=2>&gt; &gt; &nbsp;&nbsp;&nbsp; print ws</FONT>
<BR><FONT SIZE=2>&gt; &gt; &nbsp;&nbsp;&nbsp; _pyOSR.osr_exit(ws)</FONT>
<BR><FONT SIZE=2>&gt; &gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt; Here is the traceback:</FONT>
<BR><FONT SIZE=2>&gt; &gt; Traceback (most recent call last):</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp; File</FONT>
<BR><FONT SIZE=2>&gt; &gt; </FONT>
<BR><FONT SIZE=2>&gt; &quot;C:\daten\devel\sourcecode-cd\OptiSearch\src\pyOSR\msvc\Releas</FONT>
<BR><FONT SIZE=2>&gt; e\test.py&quot;,</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp; line 3, in ?</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; ws = _pyOSR.osr_init(&quot;.&quot;)</FONT>
<BR><FONT SIZE=2>&gt; &gt; TypeError: No to_python (by-value) converter found for C++ </FONT>
<BR><FONT SIZE=2>&gt; type: struct workspace_ *</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; Right.&nbsp; You asked it to dereference the workspace_ pointer and return</FONT>
<BR><FONT SIZE=2>&gt; a copy of the result inside a Python object.</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; &gt; Now I thought: ok, let's register a converter</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; extern &quot;C&quot; void</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; dealloc(PyObject* self) {</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PyObject_Del(self);</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT>
<BR><FONT SIZE=2>&gt; &gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; struct workspace_wrapper : PyObject { workspace x; };</FONT>
<BR><FONT SIZE=2>&gt; &gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; PyTypeObject workspaceType = {</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PyObject_HEAD_INIT(NULL)</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0,</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;workspace&quot;,</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sizeof(workspace_wrapper),</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0,</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dealloc</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; };</FONT>
<BR><FONT SIZE=2>&gt; &gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; struct p_from_workspace {</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static workspace &amp;execute (workspace_wrapper &amp;p_) {</FONT>
<BR><FONT SIZE=2>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ^^^^^^^^^^^</FONT>
<BR><FONT SIZE=2>&gt; Should be&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; workspace_&amp;</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return p_.x;</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; Likewise, should be return *p_.x;</FONT>
<BR><FONT SIZE=2>&gt; [see caveat below]</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; };</FONT>
<BR><FONT SIZE=2>&gt; &gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; struct pworkspace_to_python</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : to_python_converter&lt;workspace, pworkspace_to_python&gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; {</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static PyObject* convert(workspace x) {</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; workspace_wrapper *o =</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PyObject_New (workspace_wrapper, &amp;workspaceType);</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o-&gt;x = x;</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ((PyObject*) o);</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; };</FONT>
<BR><FONT SIZE=2>&gt; &gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; BOOST_PYTHON_MODULE(_pyOSR)</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; {</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pworkspace_to_python();</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lvalue_from_pytype&lt;p_from_workspace, &amp;workspaceType&gt;();</FONT>
<BR><FONT SIZE=2>&gt; &gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def (&quot;osr_init&quot;, &amp;::osr_init, </FONT>
<BR><FONT SIZE=2>&gt; return_value_policy&lt;return_by_value&gt;());</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def (&quot;osr_exit&quot;, &amp;::osr_exit);</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT>
<BR><FONT SIZE=2>&gt; &gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt; This time the output changed:</FONT>
<BR><FONT SIZE=2>&gt; &gt; &lt;workspace object at 0x00768EA0&gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt; Traceback (most recent call last):</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp; File</FONT>
<BR><FONT SIZE=2>&gt; &gt; </FONT>
<BR><FONT SIZE=2>&gt; &quot;C:\daten\devel\sourcecode-cd\OptiSearch\src\pyOSR\msvc\Releas</FONT>
<BR><FONT SIZE=2>&gt; e\test.py&quot;,</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp; line 5, in ?</FONT>
<BR><FONT SIZE=2>&gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp; _pyOSR.osr_exit(ws)</FONT>
<BR><FONT SIZE=2>&gt; &gt; TypeError: bad argument type for built-in operation</FONT>
<BR><FONT SIZE=2>&gt; &gt;</FONT>
<BR><FONT SIZE=2>&gt; &gt; The call to osr_init() succeeded and produced the expected result: a</FONT>
<BR><FONT SIZE=2>&gt; &gt; workspace object.</FONT>
<BR><FONT SIZE=2>&gt; &gt; Unfortunately the library is unable to find the proper converter for</FONT>
<BR><FONT SIZE=2>&gt; &gt; converting that object back to my workspace pointer. I'm </FONT>
<BR><FONT SIZE=2>&gt; sure, there is</FONT>
<BR><FONT SIZE=2>&gt; &gt; something obvious I'm doing wrong, but what?</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; I'm impressed with how close you got, especially considering that most</FONT>
<BR><FONT SIZE=2>&gt; of the tools you had to use are undocumented!</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; When converting from_python to a C++ pointer type, the library looks</FONT>
<BR><FONT SIZE=2>&gt; for an lvalue converter for the *pointee*.&nbsp; In other words, to convert</FONT>
<BR><FONT SIZE=2>&gt; to a Foo*, the source Python object must contain a Foo.</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; Obviously, wrapping opaque pointers is a common thing to want to do,</FONT>
<BR><FONT SIZE=2>&gt; and the library should provide a better facility for it.</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; Caveat: The code I've suggested above technically invokes undefined</FONT>
<BR><FONT SIZE=2>&gt; behavior if p_.x is 0, but I'm not aware of any platform which will</FONT>
<BR><FONT SIZE=2>&gt; have a problem with it.</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; -- </FONT>
<BR><FONT SIZE=2>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; David Abrahams</FONT>
<BR><FONT SIZE=2>&gt;&nbsp;&nbsp;&nbsp; dave@boost-consulting.com * <A HREF="http://www.boost-consulting.com" TARGET="_blank">http://www.boost-consulting.com</A></FONT>
<BR><FONT SIZE=2>&gt; Boost support, enhancements, training, and commercial distribution</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; _______________________________________________</FONT>
<BR><FONT SIZE=2>&gt; C++-sig mailing list</FONT>
<BR><FONT SIZE=2>&gt; C++-sig@python.org</FONT>
<BR><FONT SIZE=2>&gt; <A HREF="http://mail.python.org/mailman/listinfo/c++-sig" TARGET="_blank">http://mail.python.org/mailman/listinfo/c++-sig</A></FONT>
<BR><FONT SIZE=2>&gt; </FONT>
</P>

</BODY>
</HTML>