Higher abstraction level for calling C functions

Marco Leise Marco.Leise at gmx.de
Sun Jan 29 14:36:50 PST 2012


Am 29.01.2012, 21:48 Uhr, schrieb Denis Shelomovskij  
<verylonglogin.reg at gmail.com>:

> D has complete (IMHO) compiler support for calling C functions (using  
> extern(C)). But there is a lack of library support.
>
> Readers from this NG probably know this, but... Microsoft .NET Framework  
> has such support. Look briefly at source example in:
> http://msdn.microsoft.com/en-gb/library/s97shtze.aspx
>
> And at System.IO.Directory.GetCurrentDirectory source:
> http://typedescriptor.net/name/members/5540086E017CD13896E80A0CAEA6E517-System.IO.Directory.GetCurrentDirectory%28%29
> where Win32Native.GetCurrentDirectory is defined as:
> ---
> [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
> internal static extern int GetCurrentDirectory(int nBufferLength,  
> StringBuilder lpBuffer);
> ---
>
> Looks good? But it's not. It tries to provide both low level support  
> (it's needed to just call C function, like D extern(C), but do  
> everything at runtime (yes, in .NET Framework even Regex can be compiled  
> at runtime from a string)) and high level support (it converts UTF-16 to  
> ANSI in the given MSDN example). As a result it even doesn't allow you  
> to specify a (scalar) parameter as a length of another (array) parameter  
> or throw on native function failure.
>
>
>
> What can be done in that direction in D? The whole my point is expressed  
> in my small cwrap library:
> http://deoma-cmd.ru/d/docs/src/cwrap.html
>
> "Examples" is the most informative section of the documentation. Other  
> examples can be found in (original functions, all in one file):
> https://bitbucket.org/denis_sh/cwrap/src/tip/examples/c.d
> and generated wrappers:
> https://bitbucket.org/denis_sh/cwrap/src/tip/out
>
> Library state: almost every internal function is unittested, generates  
> compilable code which looks right but not unittested yet.
> NOTE: You need head dmd to CTFE it or you can just change `enum data` to  
> `auto data` in examples/c.d, this will also reduce compilation time more  
> than x10.
>
> Once original function is properly described in IDL, such library gives  
> the fallowing advantages:
> * [memory-corruption-safe] User works with arrays, not separate pointers  
> and lengths.
> * [memory-leak-safe] Original function allocated memory will be freed on  
> any failure (NOTE: see "Original function restrictions" in  
> documentation).
> * [fail-safe] An exception will be thrown if original function fails.
> * [usability] Much easier to work with arrays/preferred string types (it  
> converts UTF-8/16/32 back and forth, see docs).
> * [speed] No unnecessary GC (or other) allocations/copying/reading.
> * [garbage-free] Look at, e.g. std.file - it leaves lots of garbage  
> because of calling native platform functions. Generated wrappers don't  
> even allocate GC memory (except for output parameters).
>
> Looks like this functionality is usable for auto-generated bindings, at  
> least a useful GtkD still leaks memory almost everywhere because it  
> never frees (OK, not sure, I just haven't seen) allocated memory marked  
> by "free with g_free".
>
> So should such stuff be ever included in Phobos? IMHO yes because it's a  
> general stuff. But if not, can generated wrappers only be included and  
> used to improve current situation "a system language with a library  
> which leaves garbage"?
>
> By the way, std.file.getcwd and std.windows.charset.toMBSz are examples  
> of hand-written wrappers (the first is mine and strictly speaking forced  
> me to do this lib).
>
> P.S.
> Not sure if this library usable at all because I'm as sure in its  
> usability as in tabs indention superiority over spaces indention. )
> So if it's not (usable), tell me without scruple.
>
>
> Thanks for reading!

This idea came to me the other day when working with Windows and Posix  
API. Out of the enhancements you describe I find most useful:
- string / array conversion
- memory management
- errno / return value to exception (already implemented as a function in  
exception.d)
The only reason not to use your wrappers, is if they don't expose all  
features of the original or if you don't need D types because you pass the  
result of function A to function B directly. This could happen with some  
char* returning functions where you don't want to slow down your  
application by converting forth and back from Windows charset to UTF-8. It  
is definitely something for the "modern convenience" bullet point.


More information about the Digitalmars-d mailing list