FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Don's Compile-time Symbol Mangler
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic     Forum Index -> DDL - D Dynamic Libraries
View previous topic :: View next topic  
Author Message
Don Clugston



Joined: 05 Oct 2005
Posts: 91
Location: Germany (expat Australian)

PostPosted: Thu Nov 17, 2005 7:59 am    Post subject: Metaprogramming Reply with quote

Firstly -- looks awesome.
Secondly, this code...
---------------------
alias uint function(uint a,uint b) AddFunction;
char[] addFunctionSignature = "_D4test10testmodule3addFkkZk";

AddFunction addFunc = cast(AddFunction)(testModule.getExport(addFunctionSignature).address);
writefln("add: 42+69 = ?d",addFunc(42,69));
----------------
... is just begging for some metaprogramming support. The most basic one:

auto addFunc = testModule.getExport!(uint function(uint a, uint b))("add");

It's quite feasible that this could be entirely performed at compile time (b eneficial for code size, not execution time) Vendor-specific name mangling could even be done, if the name mangling policy was specified as a template parameter in the testModule declaration.

Potentially even more interesting, if you define

uint function(uint a, uint b) addfunc;

as a static member (which is probably what you want anyway), then
I believe it is currently feasible to write

testModule.getExport!(addfunc)("add");

(I just discovered that a static variable can be a alias template parameter).

If we could persuade Walter to add a compiler intrinsic function __nameof() or __stringize() or similar, which converted an indentifer name to a const char [],
it could even become

uint function (uint a, uint b) add;
:
testModule.getExport!(add);

which is looking rather clean.

Is any of this of interest to you? If so, I might start playing with name mangling as a practical application of my recent metaprogramming experiments.
Back to top
View user's profile Send private message
pragma



Joined: 28 May 2004
Posts: 607
Location: Washington, DC

PostPosted: Thu Nov 17, 2005 9:09 am    Post subject: Reply with quote

Quote:
Is any of this of interest to you? If so, I might start playing with name mangling as a practical application of my recent metaprogramming experiments.


I couldn't agree more that the current mode is deficient: I would love a metaprogramming or reflection facility (an intrinsic func like you mentioned) to handle name-mangling at compile time.

So I say: go forth and hack something together, and I thank you for lending a hand! Smile

Right now the project doesn't have name-mangling support so anything would be an improvement. The existing demangler in this project should provide enough of a rosetta stone for you to devise a mangling process.

Just keep in mind that one thing that may prove difficult is incorporating the complete module namespace into the mangled symbol. DDL may be able to deduce this in the future, but for now, the current mode is explicit matching of symbols only.

At worst, we're back to composing a run-time parser to generate mangled symbols from raw text, which has been on my drawing board for some time now. Please, don't be offended if such a thing crops up anyway: having this capability at runtime may prove useful as well.
_________________
-- !Eric.t.Anderton at gmail
Back to top
View user's profile Send private message Yahoo Messenger
Don Clugston



Joined: 05 Oct 2005
Posts: 91
Location: Germany (expat Australian)

PostPosted: Mon Nov 28, 2005 6:38 am    Post subject: Name mangling Reply with quote

With the release of std.demangle in DMD 0.140, the task looks much easier (in particular, everything is now documented!).

Since D still has no type info for function arguments, what I proposed isn't yet possible. But since we now have strings as template value parameters (woo hoo!), we can now do

auto addFunc = testModule.getExport!(uint, "add", uint a, uint b);

which I rather like anyway.

There's no compile time type info for classes, so it can't be pure compile-time in the general case. But it can't be pure run-time either.
Back to top
View user's profile Send private message
Don Clugston



Joined: 05 Oct 2005
Posts: 91
Location: Germany (expat Australian)

PostPosted: Tue Nov 29, 2005 2:05 am    Post subject: Name mangling proof of concept Reply with quote

OK, heres what I have so far. I wanted to avoid the triple specification of variable declaration, cast, and mangled name.
Unfortunately it seems that auto doesn't work with function pointers; would like to able to write

auto addFunc = loadFunc!(uint, "add", uint, uint);

so I wasn't completely successful. It only works with basic types and pointers; but that should be enough to play with.

USAGE:

with (mangleGroup!("test","testmodule")) {

uint function(uint, uint) addFunc = loadFunc!(uint, "add", uint, uint);
void function() hellofunc = loadFunc!(void, "helloWorld");

writefln("add: 42+69 = ?d",addFunc(42,69));
helloWorld();
}
}

(Yes, the names are stupid, it started off as just name mangling code, then I made a half-hearted attempt to eliminate the cast as well).
It might at least give you an idea of how user code might look.
-Enjoy!


FILE: meta.string
//-----------------------------------

template decimaldigit(int n) { const char [] decimaldigit = "0123456789"[n..n+1]; }

template itoa(long n)
{
static if (n<0) const char [] itoa = "-" ~ .itoa!(-n);
else static if (n<10L) const char [] itoa = decimaldigit!(n);
else const char [] itoa = .itoa!(n/10L) ~ decimaldigit!(n?10L);
}

// Workaround for DMD 0.140
template strlen(char [] str)
{
const int strlen = str.length;
}
//-----------------------------------

FILE: meta.manglearg
//-----------------------------------

// Mangle individual parameters
template mangleType(T)
{
static assert(0); // unsupported type
}

// can't use const char, result might not be known at compile time.
template mangleType(T: T*)
{ char [] mangleType = "P" ~ .mangleType!(T);
}

// Mangling of fundamental types

template mangleType(T : void)
{ const char [] mangleType = "v";
}

template mangleType(T : bit)
{ const char [] mangleType = "b";
}

template mangleType(T : byte)
{ const char [] mangleType = "g";
}

template mangleType(T : ubyte)
{ const char [] mangleType = "h";
}

template mangleType(T : short)
{ const char [] mangleType = "s";
}

template mangleType(T : ushort)
{ const char [] mangleType = "t";
}

template mangleType(T : int)
{ const char [] mangleType = "i";
}

template mangleType(T : uint)
{ const char [] mangleType = "k";
}

template mangleType(T : long)
{ const char [] mangleType = "l";
}

template mangleType(T : ulong)
{ const char [] mangleType = "m";
}

template mangleType(T : float)
{ const char [] mangleType = "f";
}

template mangleType(T : double)
{ const char [] mangleType = "d";
}

template mangleType(T : real)
{ const char [] mangleType = "e";
}

template mangleType(T : ifloat)
{ const char [] mangleType = "o";
}

template mangleType(T : idouble)
{ const char [] mangleType = "p";
}

template mangleType(T : ireal)
{ const char [] mangleType = "j";
}

template mangleType(T : cfloat)
{ const char [] mangleType = "q";
}

template mangleType(T : cdouble)
{ const char [] mangleType = "r";
}

template mangleType(T : creal)
{ const char [] mangleType = "c";
}

template mangleType(T : char)
{ const char [] mangleType = "a";
}

template mangleType(T : wchar)
{ const char [] mangleType = "u";
}

template mangleType(T : dchar)
{ const char [] mangleType = "w";
}

//-----------------------------------
Mangling for a module
//-----------------------------------

import std.stdio;

typedef void function() ExportSymbol;

void somefunc() {}

ExportSymbol LoadExport(char [] manglename)
{
writefln("Loading " ~ manglename);
return &somefunc;
};


template mangleGroup(char[] directory, char [] modulename)
{
const char [] fullname = itoa!(strlen!(directory)) ~ directory ~ itoa!(strlen!(modulename)) ~ modulename;
const char [] moduleinfo = "__ModuleInfo_" ~ fullname;

template loadFunc(RetT, char [] name)
{
RetT function() loadFunc() { return cast(RetT function() )LoadExport("_D" ~ fullname ~ itoa!(strlen!(name)) ~ name ~ "F" ~ "Z" ~ mangleType!(RetT)); }
}

template loadFunc(RetT, char [] name, P1)
{
RetT function(P1) loadFunc() { return cast(RetT function(P1))LoadExport("_D" ~ fullname ~ itoa!(strlen!(name)) ~ name ~ "F" ~ mangleType!(P1) ~ "Z" ~ mangleType!(RetT));
}
}

template loadFunc(RetT, char [] name, P1, P2)
{
RetT function(P1, P2) loadFunc() { return cast(RetT function(P1, P2))LoadExport("_D" ~ fullname ~ itoa!(strlen!(name)) ~ name ~ "F" ~ mangleType!(P1) ~ mangleType!(P2) ~ "Z" ~ mangleType!(RetT));
}
}

}

int main()
{
with (mangleGroup!("test","testmodule")) {
uint function(uint, uint) addfunc = loadFunc!(uint, "add", uint, uint);
void function() hellofunc = loadFunc!(void, "helloWorld");
creal function(char *) complexfunc = loadFunc!(creal, "moreComplex", char *);

}
return 0;
}
Back to top
View user's profile Send private message
pragma



Joined: 28 May 2004
Posts: 607
Location: Washington, DC

PostPosted: Tue Nov 29, 2005 9:29 am    Post subject: Reply with quote

Don, your skills with tempalates are amazing. I never would have thought this to be possible.

That bit with the mangleGroup!() is interesting: is that a workaround for a lack of a way to parse strings a compile-time? Seems to me that if you had template code that could split a string along the '.' characters in the identifier, that you could use namespaces of arbitrary complexity.

Once I get back to coding on DDL, your code will be in the repository. In the meantime, I'll add you to the list of contributors on the Wiki.
_________________
-- !Eric.t.Anderton at gmail
Back to top
View user's profile Send private message Yahoo Messenger
Don Clugston



Joined: 05 Oct 2005
Posts: 91
Location: Germany (expat Australian)

PostPosted: Tue Nov 29, 2005 10:02 am    Post subject: Reply with quote

[quote] I never would have thought this to be possible.[/quote]

It wasn't, until a few days ago. DMD 0.140 was an [i]awesome[/i] release. Totally leaves C++ templates for dead. What's amazing to me, is just how simple the code looks - no hacks!

[quote]
That bit with the mangleGroup!() is interesting: is that a workaround for a lack of a way to parse strings a compile-time? Seems to me that if you had template code that could split a string along the '.' characters in the identifier, that you could use namespaces of arbitrary complexity. [/quote]

No, it's pure laziness on my part. Plus I was exploring templates a bit more. In DMD 0.139, we got str[n] evaluated at compile time, so a string split function is eminently feasible. I just haven't done it yet. I didn't even get time to rename mangleGroup() into something more sensible. It could be removed entirely, so that if auto was fixed up, we could have:

[code]auto addFunc = loadFunc!(uint, "test.testmodule.add", uint, uint);
auto hellofunc = loadFunc!(void, "test.testmodule.helloWorld");

writefln("add: 42+69 = ?d",addFunc(42,69));
helloWorld();
[/code]
Then if the loaded modules are stored in a global singleton, which has an AA mapping namespaces to the loaded files, the ultimate user code could be something like:

[code]import ddl.all;

int main()
{
DDL.LoadModule("test/testmodule.obj");
auto add = loadFunc!(uint, "test.testmodule.add", uint, uint);

return add(3, 5);
}
[/code]
Back to top
View user's profile Send private message
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Tue Nov 29, 2005 12:51 pm    Post subject: Reply with quote

Yes ~ amazing indeed!

Nice one, Don. This is really great news.
Back to top
View user's profile Send private message
pragma



Joined: 28 May 2004
Posts: 607
Location: Washington, DC

PostPosted: Tue Nov 29, 2005 1:27 pm    Post subject: Reply with quote

Don Clugston wrote:
In DMD 0.139, we got str[n] evaluated at compile time, so a string split function is eminently feasible. I just haven't done it yet. I didn't even get time to rename mangleGroup() into something more sensible. It could be removed entirely[...]

Then if the loaded modules are stored in a global singleton, which has an AA mapping namespaces to the loaded files, the ultimate user code could be something like:

Code:
import ddl.all;

int main()
{
     DDL.LoadModule("test/testmodule.obj");
     auto add = loadFunc!(uint, "test.testmodule.add", uint, uint);

   return add(3, 5);
}   


Nice. Smile
That's about as clean as it gets, although the loadFunc!() should probably get attached to the loaded module.

Code:

int main()
{
     auto linker = new Linker(); // implicitly pulls in needed libs per platform
     auto module = linker.loadModule("test/testmodule.obj"); // runtime load and link
     auto add = module.loadFunc!(uint, "test.testmodule.add", uint, uint);

   return add(3, 5);
}


I can't get over how nice that looks, and to think it's a compile-time facility. This is just awesome.
_________________
-- !Eric.t.Anderton at gmail
Back to top
View user's profile Send private message Yahoo Messenger
JJR



Joined: 22 Feb 2004
Posts: 1104

PostPosted: Wed Nov 30, 2005 12:29 am    Post subject: Reply with quote

Don,

You've got the option "Disable BBCode in this post" checked, so your post is not being formated with the [code][/code] and [quote][/quote].

Nice work, though! Recently I was working on a problem similar to this and couldn't figure out a solution. Your examples above along with the 0.140 template improvements have fixed that for me. Thanks!

-JJR
Back to top
View user's profile Send private message
Don Clugston



Joined: 05 Oct 2005
Posts: 91
Location: Germany (expat Australian)

PostPosted: Wed Nov 30, 2005 3:57 am    Post subject: Reply with quote

This works. Almost reaches the goal, except for the "auto doesn't work with function pointers" bug.


Code:

/-----------------------------------
Mangling for a module
//-----------------------------------

import std.stdio;
// more workarounds for compiler bugs
template slice(char [] str, int from, int to)
{
  const char [] slice = str[from..to];
}

template concat(char [] str1, char [] str2)
{
  const char [] concat = str1 ~ str2;
}

template mangleText(char[] text, char [] latestword="")
{
  static if (text.length<1)  {
     static if (strlen!(latestword)==0)
            const char[] mangleText = "";
     else const char[] mangleText = itoa!(strlen!(latestword)) ~ latestword;
  } else static if (text[0]=='.') {
      const char[] mangleText =
      itoa!(strlen!(latestword)) ~ latestword ~ .mangleText!(slice!(text, 1, strlen!(text)), "");
  } else
     const char[] mangleText = .mangleText!( slice!(text, 1, strlen!(text)), concat!(latestword,slice!(text, 0, 1)));
}

import std.stdio;

typedef void function() ExportSymbol;

void somefunc() {}

class Module
{
  char [] fileName;
  this(char [] name) { fileName = name; }
   ExportSymbol LoadExport(char [] manglename)
   {
     writefln("Loading " ~ manglename ~ " from " ~ fileName);
     return &somefunc;
   };
   public:
template loadFunc(RetT, char [] name)
{
   RetT function() loadFunc() { return cast(RetT function() )LoadExport("_D" ~ mangleText!(name) ~ "F" ~ "Z" ~ mangleType!(RetT)); }
}

template loadFunc(RetT, char [] name, P1)
{
   RetT function(P1) loadFunc() { return cast(RetT function(P1))LoadExport("_D" ~ mangleText!(name) ~ "F" ~ mangleType!(P1) ~ "Z" ~ mangleType!(RetT));
   }
}

template loadFunc(RetT, char [] name, P1, P2)
{
   RetT function(P1, P2) loadFunc() { return cast(RetT function(P1, P2))LoadExport("_D" ~
   mangleText!(name) ~ "F" ~ mangleType!(P1) ~ mangleType!(P2) ~ "Z" ~ mangleType!(RetT));
   }
}
};

Module LoadModule(char [] modulename) {
   return new Module(modulename);
}

int main()
{
  auto m = LoadModule("testmodule.obj");

    uint function(uint, uint) addfunc = m.loadFunc!(uint, "test.testmodule.add", uint, uint);
     void function() hellofunc = m.loadFunc!(void, "test.testmodule.helloWorld");
 return add(27, 56);
}
Back to top
View user's profile Send private message
Don Clugston



Joined: 05 Oct 2005
Posts: 91
Location: Germany (expat Australian)

PostPosted: Wed Nov 30, 2005 4:58 am    Post subject: Reply with quote

My mistake, if you use 'auto' with a no-parameter function, the property behaviour is disabled. (Maybe that is a bug?) Anyway, the workaround is simple - just add (). And so THIS WORKS!

It's a great advertisement for the latest D features.

Code:
int main()
{
   auto m = LoadModule("test/testmodule.obj");

   auto add = m.loadFunc!(uint, "test.testmodule.add", uint, uint)();
   auto hello = m.loadFunc!(void, "test.testmodule.helloWorld")();

  hello();
  return add(3, 57);
}
Back to top
View user's profile Send private message
JJR



Joined: 22 Feb 2004
Posts: 1104

PostPosted: Wed Nov 30, 2005 12:01 pm    Post subject: Reply with quote

Don Clugston wrote:
Code:
int main()
{
   auto m = LoadModule("test/testmodule.obj");

   auto add = m.loadFunc!(uint, "test.testmodule.add", uint, uint)();
   auto hello = m.loadFunc!(void, "test.testmodule.helloWorld")();

  hello();
  return add(3, 57);
}


Very nice!
Back to top
View user's profile Send private message
Don Clugston



Joined: 05 Oct 2005
Posts: 91
Location: Germany (expat Australian)

PostPosted: Mon Dec 05, 2005 8:14 am    Post subject: Update for DMD 0.141 Reply with quote

Here's the COMPLETE code, updated for the fantastic new .mangleof keyword from DMD 0.141. This code works with any type.
Except...
now there are more possibilities!
We could also have, for example:

auto addfunc = m.loadFunc!(uint function (uint, uint), "test.testmodule.add")();

which is maybe not superior, but is interesting because (a) it requires much less duplication in the mangling code (you would not need overloads for each set of parameters), and (b) allows you to specify the calling convention seperately for each function (although this could be done easily enough).

Decisions, decisions...
Walter is giving us a *lot* of rope. Beautiful rope, too. Elvish, I think.
Anyway, these changes should just drop in, it just removes the caveats from the existing code.

Code:
template decimaldigit(int n) { const char [] decimaldigit = "0123456789"[n..n+1]; }

template itoa(long n)
{
         static if (n<0)  const char [] itoa = "-" ~ .itoa!(-n);
   else  static if (n<10L) const char [] itoa = decimaldigit!(n);
   else  const char [] itoa = .itoa!(n/10L) ~ decimaldigit!(n?10L);
}

// Workarounds for DMD 0.141 - shouldn't be necessary
template slice(char [] str, int from, int to)
{
  const char [] slice = str[from..to];
}

template concat(char [] str1, char [] str2)
{
  const char [] concat = str1 ~ str2;
}

template mangleText(char[] text, char [] latestword="")
{
  static if (text.length<1)  {
     static if (latestword.length==0)
            const char[] mangleText = "";
     else const char[] mangleText = itoa!(latestword.length) ~ latestword;
  } else static if (text[0]=='.') {
      const char[] mangleText =
      itoa!(latestword.length) ~ latestword ~ .mangleText!(slice!(text, 1, text.length), "");
  } else
  const char[] mangleText = .mangleText!( slice!(text, 1, text.length), concat!(latestword, slice!(text, 0, 1)) );
}

import std.stdio;

typedef void function() ExportSymbol;

void somefunc() {}

class Module
{
  char [] fileName;
  this(char [] name) { fileName = name; }
   ExportSymbol LoadExport(char [] manglename)
   {
     writefln("Loading " ~ manglename ~ " from " ~ fileName);
     return &somefunc;
   };
   public:
template loadFunc(RetT, char [] name)
{
   RetT function() loadFunc() { return cast(RetT function() )LoadExport("_D" ~ mangleText!(name) ~ "F" ~ "Z" ~ RetT.mangleof); }
}

template loadFunc(RetT, char [] name, P1)
{
   RetT function(P1) loadFunc() { return cast(RetT function(P1))LoadExport("_D" ~ mangleText!(name) ~ "F" ~ P1.mangleof ~ "Z" ~ RetT.mangleof);
   }
}

template loadFunc(RetT, char [] name, P1, P2)
{
   RetT function(P1, P2) loadFunc() { return cast(RetT function(P1, P2))LoadExport("_D" ~
   mangleText!(name) ~ "F" ~ P1.mangleof ~ P2.mangleof ~ "Z" ~ RetT.mangleof);
   }
}
};

Module LoadModule(char [] modulename) {
   return new Module(modulename);
}

int main()
{
  auto m = LoadModule("testmodule.obj");

    auto addfunc = m.loadFunc!(uint, "test.testmodule.add", uint, uint)();
    auto hellofunc = m.loadFunc!(void, "test.testmodule.helloWorld")();   
 return 0;
}
Back to top
View user's profile Send private message
Don Clugston



Joined: 05 Oct 2005
Posts: 91
Location: Germany (expat Australian)

PostPosted: Mon Dec 05, 2005 8:14 am    Post subject: Update for DMD 0.141 Reply with quote

Here's the COMPLETE code, updated for the fantastic new .mangleof keyword from DMD 0.141. This code works with any type.

Code:
template decimaldigit(int n) { const char [] decimaldigit = "0123456789"[n..n+1]; }

template itoa(long n)
{
         static if (n<0)  const char [] itoa = "-" ~ .itoa!(-n);
   else  static if (n<10L) const char [] itoa = decimaldigit!(n);
   else  const char [] itoa = .itoa!(n/10L) ~ decimaldigit!(n?10L);
}

// Workarounds for DMD 0.141 - shouldn't be necessary
template slice(char [] str, int from, int to)
{
  const char [] slice = str[from..to];
}

template concat(char [] str1, char [] str2)
{
  const char [] concat = str1 ~ str2;
}

template mangleText(char[] text, char [] latestword="")
{
  static if (text.length<1)  {
     static if (latestword.length==0)
            const char[] mangleText = "";
     else const char[] mangleText = itoa!(latestword.length) ~ latestword;
  } else static if (text[0]=='.') {
      const char[] mangleText =
      itoa!(latestword.length) ~ latestword ~ .mangleText!(slice!(text, 1, text.length), "");
  } else
  const char[] mangleText = .mangleText!( slice!(text, 1, text.length), concat!(latestword, slice!(text, 0, 1)) );
}

import std.stdio;

typedef void function() ExportSymbol;

void somefunc() {}

class Module
{
  char [] fileName;
  this(char [] name) { fileName = name; }
   ExportSymbol LoadExport(char [] manglename)
   {
     writefln("Loading " ~ manglename ~ " from " ~ fileName);
     return &somefunc;
   };
   public:
template loadFunc(RetT, char [] name)
{
   RetT function() loadFunc() { return cast(RetT function() )LoadExport("_D" ~ mangleText!(name) ~ "F" ~ "Z" ~ RetT.mangleof); }
}

template loadFunc(RetT, char [] name, P1)
{
   RetT function(P1) loadFunc() { return cast(RetT function(P1))LoadExport("_D" ~ mangleText!(name) ~ "F" ~ P1.mangleof ~ "Z" ~ RetT.mangleof);
   }
}

template loadFunc(RetT, char [] name, P1, P2)
{
   RetT function(P1, P2) loadFunc() { return cast(RetT function(P1, P2))LoadExport("_D" ~
   mangleText!(name) ~ "F" ~ P1.mangleof ~ P2.mangleof ~ "Z" ~ RetT.mangleof);
   }
}
};

Module LoadModule(char [] modulename) {
   return new Module(modulename);
}

int main()
{
  auto m = LoadModule("testmodule.obj");

    auto addfunc = m.loadFunc!(uint, "test.testmodule.add", uint, uint)();
    auto hellofunc = m.loadFunc!(void, "test.testmodule.helloWorld")();   
 return 0;
}
Back to top
View user's profile Send private message
pragma



Joined: 28 May 2004
Posts: 607
Location: Washington, DC

PostPosted: Mon Dec 05, 2005 11:11 am    Post subject: Re: Update for DMD 0.141 Reply with quote

Don Clugston wrote:
Here's the COMPLETE code, updated for the fantastic new .mangleof keyword from DMD 0.141. This code works with any type.
Except...
now there are more possibilities!
We could also have, for example:

auto addfunc = m.loadFunc!(uint function (uint, uint), "test.testmodule.add")();

which is maybe not superior, but is interesting because (a) it requires much less duplication in the mangling code (you would not need overloads for each set of parameters), and (b) allows you to specify the calling convention seperately for each function (although this could be done easily enough).


I like the new form that you propose as it would appear to eliminate the need for separate methods for fields and functions: is this still the case? At the very least, I can do away with the zillion or so template overloads to accomodate up to n function parameters.

Anyway its way more clear as it now reads "Get me a symbol of this type with this name". Great stuff.

Now if only mangleof() accepted a name as a parameter, we'd be set. In the meantime, I have you to thank Don. Smile
_________________
-- !Eric.t.Anderton at gmail
Back to top
View user's profile Send private message Yahoo Messenger
Display posts from previous:   
Post new topic   Reply to topic     Forum Index -> DDL - D Dynamic Libraries All times are GMT - 6 Hours
Goto page 1, 2, 3  Next
Page 1 of 3

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group