www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Help: running a method from the importing file's method "space"

reply "Rowan" <rowanreeve gmail.com> writes:
Hi all,

Two things first:
1) I am quite new to D and have been using Java at school and a 
bit of C++ at home so some things confuse me. Please bear with me.
2) Apologies about the ambiguity of the title, I have no idea how 
to ask this in just one line so I'll elaborate here:

What I want to do is create a static library to create a small 
wrapper/ to the Win API GUI functions for some basic GUI 
components for some projects instead of using some of the already 
made and slightly bulky GUI libraries around for D. This is what 
gives me a problem explained below.

I need the WinMain(...) entry point to be run so that I can get 
my window handle for many of the windows GUI functions so using 
main() is out, and I want WinMain to be in the library, so the 
entry point of the program is in the library not the importing 
file, so if I have my (simplified) files:

--------------
File: MyLib.d:
--------------

module MyLib;

import core.runtime;
import core.sys.windows.windows;
//import std.string;

extern(windows) {
     int WinMain(...) {
         int success;
         //Init code
         success = myWin(...);
         return success;
     }
}

int myWin(...) {
     progMain();
}

//Other code...

--------------
File: test.d (i.e. importing file):
--------------

import MyLib;

pragma(lib, "MyLib.lib");

void progMain() {
     //User TODO code...
}

So if I want to make any file (in this case "test.d", which can 
just import MyLib after I have -lib'd it and use the custom 
"entry point" -> "progMain" after "MyLib" has gotten everything 
it needs from the WinMain entry point, so that the programmer 
(me) can now just import MyLib and start typing their code in 
progMain instead of the usual main() without having to alter the 
source of MyLib. Basically I want MyLib to be able to call test's 
"progMain()", as when I try I get some error along the lines of 
progMain() not existing. I hope someone understands me, if you do 
and have an answer could you give me a step by step way of doing 
this?

Thanks

-Rowan
Apr 30 2012
next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Monday, 30 April 2012 at 18:30:29 UTC, Rowan wrote:

 --------------
 File: MyLib.d:
 --------------

 module MyLib;

 import core.runtime;
 import core.sys.windows.windows;
 //import std.string;


 So if I want to make any file (in this case "test.d", which can 
 just import MyLib after I have -lib'd it and use the custom 
 "entry point" -> "progMain" after "MyLib" has gotten everything 
 it needs from the WinMain entry point, so that the programmer 
 (me) can now just import MyLib and start typing their code in 
 progMain instead of the usual main() without having to alter 
 the source of MyLib. Basically I want MyLib to be able to call 
 test's "progMain()", as when I try I get some error along the 
 lines of progMain() not existing. I hope someone understands 
 me, if you do and have an answer could you give me a step by 
 step way of doing this?

Add 'import test;' to your MyLib module.
Apr 30 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Monday, 30 April 2012 at 18:50:24 UTC, Era Scarecrow wrote:
  Add 'import test;' to your MyLib module.

Although that seems like it's connecting a library to something it shouldn't... In which case perhaps a delegate passed to the library to call myProg? Doesn't seem right either. What is your library suppose to do? And why should it have to access something outside it's library set? (Unless test.d is part of the library)
Apr 30 2012
prev sibling next sibling parent "Rowan" <rowanreeve gmail.com> writes:
  Add 'import test;' to your MyLib module.

That does work, but I didn't want to change the source of MyLib, I dunno maybe what I'm asking isn't possible.
Apr 30 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Monday, 30 April 2012 at 19:22:35 UTC, Rowan wrote:
 Add 'import test;' to your MyLib module.

That does work, but I didn't want to change the source of MyLib, I dunno maybe what I'm asking isn't possible.

Is there a reason the library needs to call outside of it's own library access? When I think of a library it's suppose to be self contained. Perhaps just the approach is wrong?
Apr 30 2012
prev sibling next sibling parent "Rowan" <rowanreeve gmail.com> writes:
On Monday, 30 April 2012 at 18:54:41 UTC, Era Scarecrow wrote:
 On Monday, 30 April 2012 at 18:50:24 UTC, Era Scarecrow wrote:
 Add 'import test;' to your MyLib module.

Although that seems like it's connecting a library to something it shouldn't... In which case perhaps a delegate passed to the library to call myProg? Doesn't seem right either. What is your library suppose to do? And why should it have to access something outside it's library set? (Unless test.d is part of the library)

I make this library to create a few classes for creating some simple GUI components (window, buttons, text boxes, that's about it) as a bit of a learning exercise, and for practical use. "test.d" is not part of the library, it is just for testing the library. What I could do that would definatly work is: -------------- File "test.d": -------------- import core.runtime; import core.sys.windows.windows; import MyLib; pragma(lib, "MyLib.lib); extern(Windows) { WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR CmdLine, int CmdShow) { MyLibInit(hInst, hPrevInst, CmdLine, CmdShow); } ----ENDFILE---- So I can then just pass everything my lib requires to it and then there is no need for progMain. I'm asking this question as with QT's source, it uses WinMain: https://qt.gitorious.org/qt/qt/blobs/HEAD/src/winmain/qtmain_win.cpp 80 /* 81 WinMain() - Initializes Windows and calls user's startup function main(). 82 NOTE: WinMain() won't be called if the application was linked as a "console" 83 application. 84 */ 85 86 #ifdef Q_OS_WINCE 87 int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR /*wCmdParam*/, int cmdShow) Yet you can still use "main()" from your program and then link to QT's dll and use its functionality. I know that is C++ but that's where I'm comming from with this. I think you are right and my library isn't supposed to try access "test.d"'s methods, classes, etc. and be self contained. So should I rather go with the WinMain in my main program then pass the parameters to MyLib like I showed before the QT reference?
Apr 30 2012
prev sibling next sibling parent "Rowan" <rowanreeve gmail.com> writes:
With MyLib obviously containing the MyLibInit(HINSTANCE hInst, 
HINSTANCE hPrevInst, LPSTR CmdLine,
int CmdShow) method.
Apr 30 2012
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
I'm not sure if any of this is helpful but I've had a tinker and had some
measure of success :p

I think you have the following issues to resolve:
1. When you build the lib, you need to tell it that the progMain symbol is
to be found 'extern'ally.
2. When you build the exe, you have to make sure the linker goes looking
for WinMain and not main /and/ that it looks in the lib for it.

I've managed to get something "working" but it's not what you want (but it
might help you get there) and it's not pretty...

1. Add the following line to mylib.d:
             extern(C) int progMain();

             This tells dmd that when it compiles mylib.d the symbol  
progMain
is
to
be found externally, and it's C linkage (I tried D linkage, but this
prepends "MyLib" to the symbol it searches for).

2. Modify test.d and make it read:
             extern(C)
             void progMain() {

             This makes progMain a C linkage symbol, which the linker will
find
and
use.

3. Compile mylib.d with:
              dmd -c mylib

             (I know, this doesn't build a lib more on that later..)

4. Compile test.d with:
              dmd -c test

5. Run link.exe manually, e.g.

             <path to dmd bin>\link.exe
test+mylib,,nul,phobos+user32+kernel32/noi;

             This produces a test.exe which runs and executes progMain from
test.d.


Initially I was trying to get it working with a lib but I got dead-ended.

Using the code changes I mentioned above, and a test.def which reads:
             EXETYPE NT
             SUBSYSTEM WINDOWS

If you go:

             dmd -lib mylib
             dmd -c test
             link.exe test,,nul,mylib+phobos+user32+kernel32/noi,test.def;

you get:

             OPTLINK : Warning 134: No Start Address

I think that the reason for this is that test.obj does not define an entry
point, see:
             http://www.digitalmars.com/ctg/OptlinkErrorMessages.html
             (No Start Address)

This implies it is looking for entry points in object files, and perhaps
that means /not/ libs??  Not sure.


So, I tried to re-use my earlier extern trick adding:

extern(Windows)
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow);

to test.d, but that gave the same results.


References..
http://dlang.org/windows.html
http://www.digitalmars.com/ctg/optlink.html
https://github.com/AndrejMitrovic/DWinProgramming

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/
May 01 2012
prev sibling parent "Rowan" <rowanreeve gmail.com> writes:
On Tuesday, 1 May 2012 at 17:34:23 UTC, Regan Heath wrote:
 I'm not sure if any of this is helpful but I've had a tinker 
 and had some
 measure of success :p

 I think you have the following issues to resolve:
 1. When you build the lib, you need to tell it that the 
 progMain symbol is
 to be found 'extern'ally.
 2. When you build the exe, you have to make sure the linker 
 goes looking
 for WinMain and not main /and/ that it looks in the lib for it.

 I've managed to get something "working" but it's not what you 
 want (but it
 might help you get there) and it's not pretty...

 1. Add the following line to mylib.d:
             extern(C) int progMain();

             This tells dmd that when it compiles mylib.d the 
 symbol progMain
 is
 to
 be found externally, and it's C linkage (I tried D linkage, but 
 this
 prepends "MyLib" to the symbol it searches for).

 2. Modify test.d and make it read:
             extern(C)
             void progMain() {

             This makes progMain a C linkage symbol, which the 
 linker will
 find
 and
 use.

 3. Compile mylib.d with:
              dmd -c mylib

             (I know, this doesn't build a lib more on that 
 later..)

 4. Compile test.d with:
              dmd -c test

 5. Run link.exe manually, e.g.

             <path to dmd bin>\link.exe
 test+mylib,,nul,phobos+user32+kernel32/noi;

             This produces a test.exe which runs and executes 
 progMain from
 test.d.


 Initially I was trying to get it working with a lib but I got 
 dead-ended.

 Using the code changes I mentioned above, and a test.def which 
 reads:
             EXETYPE NT
             SUBSYSTEM WINDOWS

 If you go:

             dmd -lib mylib
             dmd -c test
             link.exe 
 test,,nul,mylib+phobos+user32+kernel32/noi,test.def;

 you get:

             OPTLINK : Warning 134: No Start Address

 I think that the reason for this is that test.obj does not 
 define an entry
 point, see:
             
 http://www.digitalmars.com/ctg/OptlinkErrorMessages.html
             (No Start Address)

 This implies it is looking for entry points in object files, 
 and perhaps
 that means /not/ libs??  Not sure.


 So, I tried to re-use my earlier extern trick adding:

 extern(Windows)
 int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR 
 lpCmdLine,
 int nCmdShow);

 to test.d, but that gave the same results.


 References..
 http://dlang.org/windows.html
 http://www.digitalmars.com/ctg/optlink.html
 https://github.com/AndrejMitrovic/DWinProgramming

Thank you very much for the input, I tried to do what you said and followed your instructions and went through link.exe and did get a successful compile. What you have done does work (tested it by omitting the .def file in link to get the console window and did a writeln in WinMain for mylib AND progMain for test and it does work (both wrileln's from WinMain and progMain print to console) :-). This is pretty much what I wanted, yet it is still, as you put it "not pretty", and making a lib for it isn't working. It's a bit late here, so I'll tinker around tomorrow or the day after with this and see if I can get towards more of a cleaner way of doing this, I'll post back here with what I find. Once again thank you, this seems like a nudge in the right direction. -Rowan
May 01 2012