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









Mike Parker <aldacron gmail.com> 