|
Packit |
c32a2d |
========================================================================
|
|
Packit |
c32a2d |
DYNAMIC LINK LIBRARY : mpg123clr Project Overview
|
|
Packit |
c32a2d |
========================================================================
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
Project Installation:
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
The project is part of a Visual Studio 2008 Solution.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
The Visual Studio solution file is 2008clr.sln located in a folder/directory named 2008clr.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
This folder/directory should be located in the mpg123/ports/MSVC++ folder to maintain file relationships
|
|
Packit |
c32a2d |
with required mpg123 library files. i.e. at mpg123/ports/MSVC++/2008clr.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
The solution includes the following projects:
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
mpg123clr The mpg123 CLR project. This creates the CLR compatible DLL file.
|
|
Packit |
c32a2d |
scanclr Demonstration project for comparison with scan.c example.
|
|
Packit |
c32a2d |
feedseekclr Demonstration project for comparison with feedseek.c example
|
|
Packit |
c32a2d |
replacereaderclr Demonstration project, how to implement ReplaceReader in CLR (proof of concept)
|
|
Packit |
c32a2d |
libmpg123 For convenience, ensures that libmpg123.lib is available for linking
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
=========================================================================
|
|
Packit |
c32a2d |
Compiling:
|
|
Packit |
c32a2d |
Configuration Manager:
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
mpg123clr requires linking to a libmpg123 static library, this library must be compiled prior to
|
|
Packit |
c32a2d |
compiling the clr projects. mpg123clr uses relative folder position during linking; therefore either:-
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
ensure that the 2008clr solution is correctly located within the ports\msvc++ folder, or
|
|
Packit |
c32a2d |
change the "linker->input->additional dependencies" to suit your installation configuration
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
NOTE: x64 Active Solution Platform configurations are not supplied with this solution but have been tested.
|
|
Packit |
c32a2d |
(Effectively all that is required is to change all "include" references to account for the "x64" output locations)
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
NOTE: The "unsafe" context of the ReplaceReaderClr project is only required to allow the use of callbacks.
|
|
Packit |
c32a2d |
mpg123clr is written to avoid the use of "unsafe" for the majority of normal operations.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
==========================================================================
|
|
Packit |
c32a2d |
Using mpg123clr:
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
Mpg123clr is a CLR ready dll. Simply add a reference to the mpg123clr.dll file in your application project.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
You may also add a "using" directive in your program files. C# e.g. using mpg123clr;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
The mpg123clr project is configured to create an additional Intellisense documentation file (mpg123clr.xml)
|
|
Packit |
c32a2d |
to assist usage. If you manually relocate the .dll please also copy the .xml file to ensure correct Intellisense
|
|
Packit |
c32a2d |
operation.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
===========================================================================
|
|
Packit |
c32a2d |
Common Errors:
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
1) Problem: "Unhandled Exception - file not found" error when the application is executed.
|
|
Packit |
c32a2d |
Cause: Incorrect libmpg123 library build / missing libmpg123.dll.
|
|
Packit |
c32a2d |
Solution: Copy libmpg123.dll to the application output folder - possibly in a Post-Build Event (see scanclr for
|
|
Packit |
c32a2d |
an example).
|
|
Packit |
c32a2d |
Explanation: mpg123clr requires static library libmpg123.lib and NOT dynamic library libmpg123.dll.
|
|
Packit |
c32a2d |
If the libmpg123 library is built using an incorrect Project Context (such as Debug_Generic_Dll), mpg123clr
|
|
Packit |
c32a2d |
will attempt to load the libmpg123.dll at runtime even though this file is not required.
|
|
Packit |
c32a2d |
Alternatively: Use Configuration Manager and select a non-dll build context for the libmpg123 project.
|
|
Packit |
c32a2d |
(i.e. Debug_Generic not Debug_Generic_Dll)
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
===========================================================================
|
|
Packit |
c32a2d |
Developer Notes:
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
1) Documentation <remarks> do not appear in CLR Intellisense environment (at time of writing).
|
|
Packit |
c32a2d |
So deferred in favour of <para> within <summary>.
|
|
Packit |
c32a2d |
2) During development "off_t" parameters conflicted with intellisense (although size_t worked just fine)
|
|
Packit |
c32a2d |
Since many CLR functions that refer to off_t features (e.g. positioners) actually expect 64bit long
|
|
Packit |
c32a2d |
(or long long in C++) parameters, I've implemented off_t as a long long - with one notable exception.
|
|
Packit |
c32a2d |
This fixed intellisense and accommodates the CLR 64bit long implementation positioners: And then intellisense
|
|
Packit |
c32a2d |
started working correctly and made this a moot point - at least as far as intellisense is concerned.
|
|
Packit |
c32a2d |
3) off_t notable exception - SeekDelegate, SeekHandleDelegate
|
|
Packit |
c32a2d |
Usually 2008clr functions are called by the callee, long long (clr 64bit long) can be marshaled and passed
|
|
Packit |
c32a2d |
to libmpg123. The seek delegate is called directly by the libmpg123 seek functions - there isn't an opportunity
|
|
Packit |
c32a2d |
to marshal the offending parameters. A library compiled in 32 bit will expect the SeekDelegate to have a 32bit
|
|
Packit |
c32a2d |
position parameter but in 64bit compilation the same parameter will be 64bit. Therefore the need to be correct
|
|
Packit |
c32a2d |
overrides the need for consistency with CLR 64bit positioners.
|
|
Packit |
c32a2d |
SIDE NOTE: In early tests the SeekDelegate was defined with a long long parameter - libmpg123 called it oblivious
|
|
Packit |
c32a2d |
to the fact that the type was incorrect. The only impact was that the 32bit position and 32bit origin (whence)
|
|
Packit |
c32a2d |
were compacted to a single 64bit parameter. This is fixed, no longer an issue!!!
|
|
Packit |
c32a2d |
4) PosixSeek and PosixRead ARE ONLY INCLUDED AS PROOF OF CONCEPT - to prove that the callbacks into CLR would
|
|
Packit |
c32a2d |
function correctly with libmpg123 cdecl calls. It saved making a separate dll for the posix elements.
|
|
Packit |
c32a2d |
REPEAT AFTER ME: Not for normal consumption....
|
|
Packit |
c32a2d |
5) The __clrcall decoration of mpg123clr functions is not strictly necessary for Visual Studio 2005 and later,
|
|
Packit |
c32a2d |
but has been left in for compatibility with earlier versions. See MS documentation of "double thunking"
|
|
Packit |
c32a2d |
6) Many functions use pin_ptr to pin the return variables prior to calling the libmpg123 function, this was
|
|
Packit |
c32a2d |
considered as an alternative to avoid the use of local variables with attendant overhead of
|
|
Packit |
c32a2d |
allocate/use/copy/destroy etc. In practice pin_ptr has significant overhead, empirical tests showed very
|
|
Packit |
c32a2d |
little performance difference between either method.
|
|
Packit |
c32a2d |
7) Set pin_ptr to NULL after use, to force early GC (recommended). Carried out performance trials and found
|
|
Packit |
c32a2d |
insignificant impact. Since most functions are likely to be used repeatedly decided to follow recommended usage.
|
|
Packit |
c32a2d |
If code analysis proves this to be redundant - can be removed...
|
|
Packit |
c32a2d |
(1.9.0.1 update) "insignificant" in Debug mode, quite significant if the debug overhead is removed,
|
|
Packit |
c32a2d |
i.e. Release mode. So try/finally blocks removed in favour of allocating temporary local return variable.
|
|
Packit |
c32a2d |
8) (1.12.0.0 update) Support for mpg123_open_handle warrants further description... here it is.
|
|
Packit |
c32a2d |
a) Pinning of delegates is not required. See Microsoft: C++, How to: Marshal Callbacks and Delegates Using C++ Interop
|
|
Packit |
c32a2d |
b) Pinning of objects is an entirely different matter, so why is the open_handle object not pinned?
|
|
Packit |
c32a2d |
Answer: Because it's an object. I allowed passing of any object not just handles.
|
|
Packit |
c32a2d |
i) a pin_ptr cannot be a field member for instance scope.
|
|
Packit |
c32a2d |
ii) cannot pin the object itself because there's no object.field to pin
|
|
Packit |
c32a2d |
iii) cannot pin the object target because the referenced object may be unblittable.
|
|
Packit |
c32a2d |
iv) GCHandle.Alloc(obj, GCHandleType.Pinned) doesn't work on unblittable objects (eg managed references like BinaryReader)
|
|
Packit |
c32a2d |
Since I don't restrict which objects may be passed I'm forced to exclude pinning.
|
|
Packit |
c32a2d |
c) The generated handle doesn't need to be pinned. GCHandle.Alloc(obj) creates a potentially GC relocatable object
|
|
Packit |
c32a2d |
containing a Handle to the object. The GCHandle.ToIntPtr(userObjectHandle) creates an integer representation of the
|
|
Packit |
c32a2d |
handle that is valid irrespective of any GC relocation of either the object or the GCHandle and can therefore be
|
|
Packit |
c32a2d |
passed through unmanaged code to CLR native methods that can re-reference the original object via GCHandle.FromIntPtr
|
|
Packit |
c32a2d |
and gch.Target.
|
|
Packit |
c32a2d |
All this seems relatively efficient, certainly there is little performance difference between the ReplaceReader
|
|
Packit |
c32a2d |
and ReplaceReaderHandle sample code.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
=============================================================================
|
|
Packit |
c32a2d |
Tested/Untested
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
I haven't used mpg123clr in a production project yet, although one is about to start. Therefore EVERYTHING should
|
|
Packit |
c32a2d |
be treated as though unproven. UPDATE: the scanclr, feedseekclr and replacereaderclr examples have provided a basic
|
|
Packit |
c32a2d |
functional test.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
Largefile support totally untested... would appreciate a volunteer.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
The majority of functions have been tried in test projects with the following exceptions.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
64bit compilation. mpg123clr compiles correctly in 64bit x64 platform mode, but hasn't been tested.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
ICY(icy_meta); Never had genuine ICY data to test with.
|
|
Packit |
c32a2d |
Icy2Utf8(icy_text); Never tried. Please provide sample material.
|
|
Packit |
c32a2d |
enc_from_id3(encbyte); Works on libmpg123 enums, never had real world text samples.
|
|
Packit |
c32a2d |
store_utf8(...); Works with CLR generated text, not tried with real world text samples.
|
|
Packit |
c32a2d |
mpg123str.strlen(...) Not tested with utf8 text strings. Please provide sample material.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
==============================================================================
|
|
Packit |
c32a2d |
Documentation
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
mpg123clr is 90% documentation, use intellisense as your reference. If in doubt refer back to the libmpg123
|
|
Packit |
c32a2d |
documents. NOTE: You need to build the mpg123clr library to create the intellisense file.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
===============================================================================
|
|
Packit |
c32a2d |
Error Trapping
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
libmpg123 is an error agnostic library - it shouldn't generate errors, but neither does it trap them.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
mpg123clr is built on the same concept although some CLR generated errors have been trapped. My personal
|
|
Packit |
c32a2d |
preference is that exceptions should be avoided not relied on...
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
THE CALLING APPLICATION IS RESPONSIBLE FOR ERROR DETECTION, TRAPPING AND CORRECTION.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
All projects are "as is" with no express or implied warranty. Demonstration projects are to demonstrate the
|
|
Packit |
c32a2d |
use of the library and are NOT considered examples of good coding practice. Use at own risk.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
===============================================================================
|
|
Packit |
c32a2d |
Revision History
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
1.8.1.0 04-Aug-09 Initial release.
|
|
Packit |
c32a2d |
1.9.0.0 24-Sep-09 Function names harmonized with libmpg123 (mb)
|
|
Packit |
c32a2d |
1.9.0.0 30-Sep-09 Project config - if exists, copy libmpg123.dll to app output folder (mb)
|
|
Packit |
c32a2d |
1.9.0.0 01-Oct-09 Technical cleanup - subst nullptr for NULL (mb)
|
|
Packit |
c32a2d |
1.9.0.1 24-Nov-09 Performance update - removed try/finally (mb)
|
|
Packit |
c32a2d |
1.12.0.0 14-Apr-10 Release match - added open_handle and framebyframe support (mb)
|
|
Packit |
c32a2d |
1.13.0.0 13-Jan-11 Release match - added encsize and strlen support (mb)
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
Constructive feedback preferred.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
Malcolm Boczek
|
|
Packit |
c32a2d |
mpg123clr original author.
|