www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Abstractioning away main/winMain

reply "Prudence" <Pursuit Happyness.All> writes:
Standard and Win32 apps are so old school!

I'd like to hide WinMain by wrapping it in an application 
class(more or less).

Essentially I have an Application class

class Application
{
    public static Application New(void delegate() entry)
    {

    }
}


.... Another module

extern (Windows) int WinMain(...)
{


}

.... User Module:


const MyApp = Application.New({ std.stdio.writeln("MY APP IS 
COOL"); });


But the lamba runs into a problem because of the static nature of 
the program... much less figuring out how to hook WinMain up into 
it.

Essentially I don't want the user ever to have to know how there 
entry point came into being but there is this funkyness about it 
because Application never gets any control to call the user's 
Entry function. Whats worse is that D tries to evaluate the 
lambda at compile time. It's as if D only allows non-static data 
inside functions.


The idea is to have WinMain actually call the Entry lamba 
function once it gets ran(transfer control)... but this seems to 
be difficult or impossible with D and I'm not sure why or, if 
not, how to get it to work without having to make the user jump 
through hoops.

I suppose I could create the Application(Using New instead of 
new) inside of WinMain, but the issue still remains on how to get 
the user entry point(I suppose some compile time reflection could 
be used?).

Any ideas?

(The main reason for doing this is to make it easier for writing 
portable apps)
Sep 04 2015
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Saturday, 5 September 2015 at 01:43:43 UTC, Prudence wrote:
 extern (Windows) int WinMain(...)
If you use WinMain in D, you'll also have to initialize the D runtime yourself, which will call static constructors and such. You'd be better off just using a regular main() function, then passing the `-L/SUBSYSTEM:WINDOWS:5.0` option to dmd when building (at least on 32 bit, not sure if it is the same on 64 bit or not) so the linker makes a gui app - same as it does when it detects a WinMain in the program.
 const MyApp = Application.New({ std.stdio.writeln("MY APP IS 
 COOL"); });
Remember, gui apps don't necessarily have a console, so writeln may fail!
 (The main reason for doing this is to make it easier for 
 writing portable apps)
Just using a regular main function is the most portable solution. Then just offer helper functions or something to help with the boilerplate.
Sep 04 2015
parent reply "Prudence" <Pursuit Happyness.All> writes:
On Saturday, 5 September 2015 at 01:49:22 UTC, Adam D. Ruppe 
wrote:
 On Saturday, 5 September 2015 at 01:43:43 UTC, Prudence wrote:
 extern (Windows) int WinMain(...)
If you use WinMain in D, you'll also have to initialize the D runtime yourself, which will call static constructors and such. You'd be better off just using a regular main() function, then passing the `-L/SUBSYSTEM:WINDOWS:5.0` option to dmd when building (at least on 32 bit, not sure if it is the same on 64 bit or not) so the linker makes a gui app - same as it does when it detects a WinMain in the program.
 const MyApp = Application.New({ std.stdio.writeln("MY APP IS 
 COOL"); });
Remember, gui apps don't necessarily have a console, so writeln may fail!
Maybe, but the error relates to be being called statically.
 (The main reason for doing this is to make it easier for 
 writing portable apps)
Just using a regular main function is the most portable solution. Then just offer helper functions or something to help with the boilerplate.
Essentially that is what I'm doing. I have divided the app into different types using versioning. The application class is a generic wrapper for the main possibilities(win32, Win64, mac, linux, etc). Basically WinMain is used when version is Win32 or Win64 so it is not a problem with the stuff you have mentioned. At some point I will make it all work but I need to get off the ground first. I can always force the user to jump through some hoops but I'd like to avoid that as much as possible since I'm the user and I don't like hoops.
Sep 04 2015
parent reply "Prudence" <Pursuit Happyness.All> writes:
If I use functions instead of delegates it works.

I suppose the problem then is that the delegate can't create a 
fat pointer when used in a static context. (i.e., why the 
functions work)

The question is, then, Can I construct a delegate manually and 
supply my own context pointer?

e.g.,
class X { }

void foo() { }

constructDelegate(&foo, new X()) // Creates a void delegate() 
with context X
Sep 04 2015
parent "Alex Parrill" <initrd.gz gmail.com> writes:
On Saturday, 5 September 2015 at 02:29:05 UTC, Prudence wrote:
 If I use functions instead of delegates it works.

 I suppose the problem then is that the delegate can't create a 
 fat pointer when used in a static context. (i.e., why the 
 functions work)

 The question is, then, Can I construct a delegate manually and 
 supply my own context pointer?

 e.g.,
 class X { }

 void foo() { }

 constructDelegate(&foo, new X()) // Creates a void delegate() 
 with context X
How would the X instance get passed in? You could try this: class X {} void foo(X x) {} auto x = new X(); auto dg = () => foo(x);
Sep 04 2015
prev sibling next sibling parent reply anonymous <anonymous example.com> writes:
On Saturday 05 September 2015 03:43, Prudence wrote:

 Standard and Win32 apps are so old school!
 
 I'd like to hide WinMain by wrapping it in an application
 class(more or less).
 
 Essentially I have an Application class
 
 class Application
 {
     public static Application New(void delegate() entry)
     {
 
     }
 }
 
 
 .... Another module
 
 extern (Windows) int WinMain(...)
 {
 
 
 }
 
 .... User Module:
 
 
 const MyApp = Application.New({ std.stdio.writeln("MY APP IS
 COOL"); });
 
 
 But the lamba runs into a problem because of the static nature of
 the program... much less figuring out how to hook WinMain up into
 it.
Please provide self-contained code. Without key details it's hard to understand where things are going wrong. I'm guessing your actual code essentially tries to do this: ---- class Application { void delegate() entry; public static Application New(void delegate() entry) { auto a = new Application; a.entry = entry; return a; } } const MyApp = Application.New({import std.stdio; std.stdio.writeln("MY APP IS COOL"); }); /* Error: non-constant nested delegate literal expression __lambda6 */ void main() /* or WinMain */ { MyApp.entry(); } ---- This doesn't work because delegates and static initialization don't go together. You can use a static constructor: ---- const Application MyApp; static this() { Application.New({import std.stdio; std.stdio.writeln("MY APP IS COOL"); }); } ---- Or you can make `entry` a function instead of a delegate: ---- class Application { void function() entry; public static Application New(void function() entry) { ... } } ----
 Essentially I don't want the user ever to have to know how there
 entry point came into being but there is this funkyness about it
 because Application never gets any control to call the user's
 Entry function. Whats worse is that D tries to evaluate the
 lambda at compile time. It's as if D only allows non-static data
 inside functions.
 
 
 The idea is to have WinMain actually call the Entry lamba
 function once it gets ran(transfer control)... but this seems to
 be difficult or impossible with D and I'm not sure why or, if
 not, how to get it to work without having to make the user jump
 through hoops.
 
 I suppose I could create the Application(Using New instead of
 new) inside of WinMain, but the issue still remains on how to get
 the user entry point(I suppose some compile time reflection could
 be used?).
 
 Any ideas?
I'm probably being naive and the following falls short somehow, but how about this: ---- /* your module */ void function() userMain; void main() /* or WinMain */ { /* ... stuff ... */ userMain(); /* ... stuff ... */ } /* user module: */ /* import your module; */ static this() { userMain = {import std.stdio; std.stdio.writeln("MY APP IS COOL"); }; } ----
Sep 04 2015
parent anonymous <anonymous example.com> writes:
On Saturday 05 September 2015 07:52, anonymous wrote:

 This doesn't work because delegates and static initialization don't go
 together. You can use a static constructor:
 
 ----
 const Application MyApp;
 static this()
 {
     Application.New({import std.stdio; std.stdio.writeln("MY APP IS
     COOL");
Should be: MyApp = Application.New({...});
 });
 }
 ----
Sep 04 2015
prev sibling parent "Kagamin" <spam here.lot> writes:
On Saturday, 5 September 2015 at 01:43:43 UTC, Prudence wrote:
 Any ideas?
See how vibe does it.
Sep 07 2015