digitalmars.D.learn - AutoDLL
- FoxyBrown (189/189) Jul 06 2017 A DLL Loader prototype that loads DLL's, just specify the
- Mike Parker (8/10) Jul 06 2017 Probably just a OMF/COFF issue. If you try to link with a COFF
- Mike Parker (2/3) Jul 06 2017 *to use* the MS linker
- FoxyBrown (7/18) Jul 06 2017 I tried some of that stuff and it didn't work so I gave up and
- FoxyBrown (103/103) Jul 06 2017 Here is a solution that will wrap all extern C functions and
A DLL Loader prototype that loads DLL's, just specify the declaration. Probably should be worked up so it is easy to load DLL's. Example: import portaudio; import std.conv, std.stdio; import core.stdc.stdio; //pragma(lib, "portaudio_x86.lib"); // Doesn't work because libs are invalid alias BOOL = ubyte; alias DWORD = uint; struct dllimport { string dllName; } template hasAttribute(alias sym, T) { static bool helper() { foreach(a; __traits(getAttributes, sym)) { if(is(a == T) || __traits(compiles, typeof(a)) && is(typeof(a) == T)) return true; } return false; } enum bool hasAttribute = helper(); } template getAttribute(alias sym, T) { static T helper() { foreach(a; __traits(getAttributes, sym)) { static if(is(a == T) || __traits(compiles, typeof(a)) && is(typeof(a) == T)) return a; } assert(0, "attribute " ~ T.stringof ~ " not found"); } enum T getAttribute = helper(); } void doImport(alias T)() { import core.sys.windows.windows, std.conv; bool isDLLLoaded = false; HINSTANCE dll; foreach(m; __traits(allMembers, T)) { static if(__traits(compiles, typeof(__traits(getMember, T, m)))) { static if(hasAttribute!(__traits(getMember, T, m), dllimport)) { auto dllName = getAttribute!(__traits(getMember, T, m), dllimport).dllName; if (!isDLLLoaded) { writeln("Loading DLL `"~dllName~"'..."); isDLLLoaded = true; dll = LoadLibrary(to!wstring(dllName~"\0").ptr); if (dll == null) { // ERROR, handle writeln("Error, aborting!"); return; } } auto q = GetProcAddress(dll, m); mixin(m~" = cast(typeof("~m~"))q;"); //func(m, getAttribute!(__traits(getMember, T, m), dllimport).dllName, cast(void**)&__traits(getMember, T, m)); } } } } mixin template DllImportFunctions() { struct DllImporter { shared static this() { doImport!(__traits(parent, DllImporter))(); } static loadFunction(string name, const(char)[] dllName, void** addr) { printf("import %.*s from %.*s into %llx\n", name.length, name.ptr, dllName.length, dllName.ptr, addr); } } } extern(Windows) dllimport("portaudio_x86.dll") __gshared { PaError function() Pa_Initialize; PaError function() Pa_Terminate; PaHostApiIndex function() Pa_GetHostApiCount; PaHostApiIndex function() Pa_GetDefaultHostApi; PaDeviceIndex function() Pa_GetDefaultOutputDevice; PaDeviceIndex function() Pa_GetDefaultInputDevice; PaDeviceIndex function() Pa_GetDeviceCount; const(PaHostErrorInfo)* function() Pa_GetLastHostErrorInfo; PaDeviceIndex function(PaHostApiIndex hostApi, int hostApiDeviceIndex ) Pa_HostApiDeviceIndexToDeviceIndex; PaHostApiIndex function(PaHostApiTypeId type) Pa_HostApiTypeIdToHostApiIndex; const(PaHostApiInfo)* function(PaHostApiIndex hostApi) Pa_GetHostApiInfo; PaError function(PaStream *stream, PaStreamFinishedCallback streamFinishedCallback) Pa_SetStreamFinishedCallback; PaError function(PaStream *stream) Pa_CloseStream; PaError function(PaStream** stream, int numInputChannels, int numOutputChannels, PaSampleFormat sampleFormat, double sampleRate, ulong framesPerBuffer, PaStreamCallback streamCallback, void *userData) Pa_OpenDefaultStream; PaError function(PaStream** stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, ulong framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback streamCallback, void *userData) Pa_OpenStream; PaError function(const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate) Pa_IsFormatSupported; const(PaDeviceInfo)* function(PaDeviceIndex device) Pa_GetDeviceInfo; PaError function(PaStream *stream) Pa_StartStream; PaError function(PaStream *stream) Pa_StopStream; PaError function(PaStream *stream) Pa_AbortStream; PaError function(PaStream *stream) Pa_IsStreamStopped; void function(long msec) Pa_Sleep; PaError function(PaSampleFormat format) Pa_GetSampleSize; long function(PaStream* stream) Pa_GetStreamWriteAvailable; long function(PaStream* stream) Pa_GetStreamReadAvailable; PaError function(PaStream* stream, const void *buffer, ulong frames) Pa_WriteStream; PaError function(PaStream* stream, void *buffer, ulong frames) Pa_ReadStream; double function(PaStream* stream) Pa_GetStreamCpuLoad; PaTime function(PaStream *stream) Pa_GetStreamTime; const(PaStreamInfo)* function(PaStream *stream) Pa_GetStreamInfo; PaError function(PaStream *stream) Pa_IsStreamActive; } mixin DllImportFunctions; struct Phase { float left=0, right=0; } extern(C) int sawtooth(const(void)* inputBuffer, void* outputBuffer, size_t framesPerBuffer, const(PaStreamCallbackTimeInfo)* timeInfo, PaStreamCallbackFlags statusFlags, void *userData) { auto phase = cast(Phase*)userData; auto pout = cast(float*)outputBuffer; enum vol = 0.2f; foreach(i; 0 .. framesPerBuffer) { *pout++ = vol * phase.left; *pout++ = vol * phase.right; phase.left += 0.01f; if (phase.left >= 1.0f) phase.left -= 2.0f; phase.right += 0.03f; if (phase.right >= 1.0f) phase.right -= 2.0f; } return 0; } int main() { enum SAMPLE_RATE = 44100; enum NUM_SECONDS = 15; PaStream* stream; PaError err; Phase phase_data; auto x = Pa_Initialize; if ((err = Pa_Initialize()) != paNoError) goto Lerror; if ((err = Pa_OpenDefaultStream(&stream, 0, 2, paFloat32, SAMPLE_RATE, paFramesPerBufferUnspecified, &sawtooth, &phase_data)) != paNoError) goto Lerror; if ((err = Pa_StartStream(stream)) != paNoError) goto Lerror; Pa_Sleep(NUM_SECONDS * 1000); if ((err = Pa_StopStream(stream)) != paNoError) goto Lerror; if ((err = Pa_CloseStream(stream)) != paNoError) goto Lerror; if ((err = Pa_Terminate()) != paNoError) goto Lerror; return 0; Lerror: //stderr.writefln("error %s", to!string(Pa_GetErrorText(err))); return 1; }
Jul 06 2017
On Thursday, 6 July 2017 at 12:15:57 UTC, FoxyBrown wrote://pragma(lib, "portaudio_x86.lib"); // Doesn't work because libs are invalidProbably just a OMF/COFF issue. If you try to link with a COFF library while compiling with 32-bit DMD in its default configuration on Windows, you'll get such errors. You'll need to compile with -m32mscoff MS linker instead. Either that, or run coffimplib [1] (doc at [2]) on the portaudio dll. [1] http://ftp.digitalmars.com/coffimplib.zip [2] http://www.digitalmars.com/ctg/coffimplib.html
Jul 06 2017
On Thursday, 6 July 2017 at 16:14:18 UTC, Mike Parker wrote:to compile with -m32mscoff MS linker instead. Either that, or*to use* the MS linker
Jul 06 2017
On Thursday, 6 July 2017 at 16:14:18 UTC, Mike Parker wrote:On Thursday, 6 July 2017 at 12:15:57 UTC, FoxyBrown wrote:I tried some of that stuff and it didn't work so I gave up and found the code above but it only printed the names so I added the ability to load the functions. I kept on getting that the was invalid. I figured it was more of a mess to try to get the libs right since what if I need to use a coff and omf? Seems like a royal pain in the butt to deal with.//pragma(lib, "portaudio_x86.lib"); // Doesn't work because libs are invalidProbably just a OMF/COFF issue. If you try to link with a COFF library while compiling with 32-bit DMD in its default configuration on Windows, you'll get such errors. You'll need to compile with -m32mscoff MS linker instead. Either that, or run coffimplib [1] (doc at [2]) on the portaudio dll. [1] http://ftp.digitalmars.com/coffimplib.zip [2] http://www.digitalmars.com/ctg/coffimplib.html
Jul 06 2017
Here is a solution that will wrap all extern C functions and allow one to then map them to a dll. auto BuildDLLClassFromCHeader(alias modulename, string name)() { import std.traits, std.algorithm, std.meta; auto s = "extern (C) class " ~name~"\n{\n\timport ___import = "~moduleName!modulename~";\n"; mixin("import "~moduleName!modulename~";"); foreach(m; AliasSeq!(__traits(allMembers, modulename))) { mixin("alias member = " ~ fullyQualifiedName!(modulename) ~ "." ~ m ~ ";"); static if (is(typeof(member) == function)) static if (functionLinkage!member != "C") continue; else s ~= "\tpublic static typeof(___import."~__traits(identifier, member)~")* "~__traits(identifier, member)~";\n"; } return s ~ "}"; } void DllImport(alias T)(string dllName) { import core.sys.windows.windows, std.conv, std.meta; auto dll = LoadLibrary(to!wstring(dllName~"\0").ptr); if (dll == null) assert(0, "Cannot load DLL `"~dllName~"'"); foreach(fname; __traits(derivedMembers, T)) { auto func = GetProcAddress(dll, fname); enum s = "auto p = cast(void**)&"~T.stringof~"."~fname~"; *p = cast(typeof(p))func;"; mixin(s); } } e.g., mixin(BuildDLLClassFromCHeader!(portaudio, "PortAudioDLL")()); DllImport!PortAudioDLL("portaudio_x86.dll"); it generates the following for portaudio.di: extern (C) class PortAudioDLL { import ___import = portaudio; public static typeof(___import.Pa_GetVersion)* Pa_GetVersion; public static typeof(___import.Pa_GetVersionText)* Pa_GetVersionText; public static typeof(___import.Pa_GetErrorText)* Pa_GetErrorText; public static typeof(___import.Pa_Initialize)* Pa_Initialize; public static typeof(___import.Pa_Terminate)* Pa_Terminate; public static typeof(___import.Pa_GetHostApiCount)* Pa_GetHostApiCount; public static typeof(___import.Pa_GetDefaultHostApi)* Pa_GetDefaultHostApi; public static typeof(___import.Pa_GetHostApiInfo)* Pa_GetHostApiInfo; public static typeof(___import.Pa_HostApiTypeIdToHostApiIndex)* Pa_HostApiTypeIdToHostApiIndex; public static typeof(___import.Pa_HostApiDeviceIndexToDeviceIndex)* Pa_HostApiDeviceIndexToDeviceIndex; public static typeof(___import.Pa_GetLastHostErrorInfo)* Pa_GetLastHostErrorInfo; public static typeof(___import.Pa_GetDeviceCount)* Pa_GetDeviceCount; public static typeof(___import.Pa_GetDefaultInputDevice)* Pa_GetDefaultInputDevice; public static typeof(___import.Pa_GetDefaultOutputDevice)* Pa_GetDefaultOutputDevice; public static typeof(___import.Pa_GetDeviceInfo)* Pa_GetDeviceInfo; public static typeof(___import.Pa_IsFormatSupported)* Pa_IsFormatSupported; public static typeof(___import.Pa_OpenStream)* Pa_OpenStream; public static typeof(___import.Pa_OpenDefaultStream)* Pa_OpenDefaultStream; public static typeof(___import.Pa_CloseStream)* Pa_CloseStream; public static typeof(___import.Pa_SetStreamFinishedCallback)* Pa_SetStreamFinishedCallback; public static typeof(___import.Pa_StartStream)* Pa_StartStream; public static typeof(___import.Pa_StopStream)* Pa_StopStream; public static typeof(___import.Pa_AbortStream)* Pa_AbortStream; public static typeof(___import.Pa_IsStreamStopped)* Pa_IsStreamStopped; public static typeof(___import.Pa_IsStreamActive)* Pa_IsStreamActive; public static typeof(___import.Pa_GetStreamInfo)* Pa_GetStreamInfo; public static typeof(___import.Pa_GetStreamTime)* Pa_GetStreamTime; public static typeof(___import.Pa_GetStreamCpuLoad)* Pa_GetStreamCpuLoad; public static typeof(___import.Pa_ReadStream)* Pa_ReadStream; public static typeof(___import.Pa_WriteStream)* Pa_WriteStream; public static typeof(___import.Pa_GetStreamReadAvailable)* Pa_GetStreamReadAvailable; public static typeof(___import.Pa_GetStreamWriteAvailable)* Pa_GetStreamWriteAvailable; public static typeof(___import.Pa_GetSampleSize)* Pa_GetSampleSize; public static typeof(___import.Pa_Sleep)* Pa_Sleep; } and then maps the function pointers to the dll. Should work for other dlls.
Jul 06 2017