Assembler: Für was/aktuell? Lernen wo, wie?



  • dot schrieb:

    masm schrieb:

    Die Größe ist heut zu tage nur noch in wenigen Fällen von Bedeutung.

    Ist das so? Ich würde mal behaupten, die Größe ist vor allem heutzutage immer mehr von Bedeutung. Denn die CPUs werden immer schneller, die Speicher aber nicht. Google mal nach Instruction Cache...

    Der (code-) cache ist stetig mit den CPU Generationen gewachsen und, gemäß sein Natur, auch sein Geschwindigkeit. Auser in sehr kleine Schleifen (<= 32Byte), machte meiner Erfahrung nach die Befehlsgröße keinen Unterschied mehr. Typisches Beispiel: add eax,1 und inc eax ... wenn man nicht grade für den Pentium 4 programmiert, ist reine Geschmackssache – einen Geschwindigkeitsunterscheide habe ich in (sinnvollen) Algorithmen noch nie festgestellt (genau wie bei XOR vs. MOV).



  • Intel sieht das anders. Nicht nur bei xor vs. mov, sondern auch bei inc vs add:

    Intel Optimization Manual schrieb:

    Assembly/Compiler Coding Rule 33. (M impact, H generality) INC and DEC instructions should be replaced with ADD or SUB instructions, because ADD and SUB overwrite all flags, whereas INC and DEC do not, therefore creating false dependencies on earlier instructions that set the flags.

    😉

    Ich würde mal sagen, gerade in kleinen Schleifen machts keinen Unterschied, weil der ganze Code sowieso im Cache bleibt. Interessant wird das, wenn man mal das Programm als ganzes betrachtet. Die Caches sind nicht wirklich soviel größer, eine SandyBridge CPU hat sogar einen kleineren L2-Cache als mancher Pentium 4. Und selbst wenn, der Speicher ist trotzdem nicht wirklich schneller geworden. Außerdem ist der unterste Cache normalerweise shared und muss alle Cores füttern (mittlerweile gibts da ja mehr als einen von). Und das Problem ist auch nicht der Cache, sondern alles was nicht im Cache ist 😉



  • Naja, logisch verknüpfte Operationen wie xor und co gehören natürlich zum Allerletzten, was man bei der Asm-Programmierung lernt, falls überhaupt...Und es hat vermutlich auch noch nie Leute gegeben, die Assembler direkt über den C-Compiler gelernt haben...🙄

    Muss das jetzt eigentlich sein, dass ihr euch an so einem Quark festbeißen müsst?
    mov ax,0 wird auch gerne für Anfänger geschrieben, die noch gar keine logischen-Verknüpf-Asm-Befehle kennen oder vielleicht um die Lesbarkeit des Codes hier und da zu erleichtern. Früher, in DOS-286 Zeiten, waren xor Befehle schneller, aber mit dem Pentium und stärkerer Risc-Bauform spielen ganz andere Punkte eine Rolle.

    Ethon liegt mehrfach daneben, u.a., wie oben schon erwähnt und mit der Annahme, dass heutzutage mit Asm in 286er Realmode Zeit und auf Anfängerniveau programmiert wird und dagegen mit C++ in 2011 mit Performanceoptimierern und Profilern. Viele Asm-Einführungen arbeiten mit Dos auf 286er Niveau und Realmode, einfach, weil es fundamentale Grundlagen sind, die man schnell lernt und die sich relativ einfach auf neuere Entwicklungen übertragen lassen. Das ist so ähnlich, wie wenn beim C++ Anfang nur Konsoleprogramme geschrieben werden. Daraus eine Philosophie über Assembler vs C++ zu entwickeln ist dann so ähnlich tiefschürfend, als würde man schreiben, mit Blitzbasic lassen sich tolle Spiele entwickeln, mit C++ nur Konsolezeugs.

    Es ist auch ein Irrtum, zu glauben, dass Assemblerprofis nur in Assembler programmieren und nicht wüßten, was so ein C-Compiler rausspuckt oder umgekehrt, dass gute C-Profis kein Assembler könnten oder bräuchten.



  • Naja, logisch verknüpfte Operationen wie xor und co gehören natürlich zum Allerletzten, was man bei der Asm-Programmierung lernt, falls überhaupt...Und es hat vermutlich auch noch nie Leute gegeben, die Assembler direkt über den C-Compiler gelernt haben...🙄

    Hey, xor war doch nur ein Beispiel. 😉
    Es geht mir einfach um Dinge, die als Mensch nicht direkt intuitiv wirken, gibt ja viel wüstere Dinge, die ein Compiler anstellt.

    dass heutzutage mit Asm in 286er Realmode Zeit und auf Anfängerniveau programmiert wird und dagegen mit C++ in 2011 mit Performanceoptimierern und Profilern.

    Gibt es denn optimierende Assembler? Wüsste nicht davon, mal einen gesehen zu haben.
    Und nein, so schlecht hab ich Assembler nicht dargestellt, und wenn doch, wars nicht beabsichtigt.

    Zum Rest: Ich kann durchaus Assembler, Reverse Engineering ist ein Hobby von mir. Trotzdem sehe ich mich durchaus in der Lage C++ Code zu schreiben, der ASM-Code in Sachen Performance nicht nachsteht.

    Der einzige Standpunkt, der hier von mir vertreten wird, ist dass ASM kein Muss für möglichst performanten Code ist, mehr nicht.



  • Ethon_notloggedin schrieb:

    Gibt es denn optimierende Assembler? Wüsste nicht davon, mal einen gesehen zu haben.

    Das überrascht leider nicht, denn man sieht den optimierenden Teil in aller Regel im Spiegel.

    Ethon_notloggedin schrieb:

    Zum Rest: Ich kann durchaus Assembler, Reverse Engineering ist ein Hobby von mir. Trotzdem sehe ich mich durchaus in der Lage C++ Code zu schreiben, der ASM-Code in Sachen Performance nicht nachsteht.

    Sag ich doch. Und es ist auch logisch. Du benutzt einen C++ Compiler, der etliche Effizienzevolutionen hinter sich hat, und setzt deine eigenen gegen Null tendierenden Assemblerprogrammierkenntnisse dagegen. (Also wenn dich schon xors im Compilerout überraschen...;) )

    Das einzige Heilmittel dagegen ist, mehr zu lernen und mehr zu üben. Ob nun C++, Java oder Assembler, das ist schnuppe. Aber je mehr du weißt(und abguckst) und je mehr du geübt hast, desto effektiveren Code kannst du programmieren.

    Es ist aber nicht wirklich schlimm, wenn man mal von Vorurteil zu Vorurteil hier im Asm-Forum hoppelt, das ist das normalste von der Welt 😉



  • Ich finde den Vergleich von Assembler und anderen Hoch-Sprachen ziemlich witzlos.
    Als Mensch, z.B. das Intel-Compiler-Optimizer-Team, hat man theoretisch immer die Möglichkeit die CPU besser auszunutzen als ein Optimizer, da man Sinn und Ziel vom Code kennt.
    Kein Mensch kommt aber auf die Idee für den PC (Win,Linux,...) eine Applikation in Assembler zu entwickeln.
    Anders sieht das in der Industrie aus, wenn eine selbstentwickelte Hardware, mit irgendeiner CPU/GPU/DSP,..., womöglich ohne eigenes Betriebsystem, zigtausendmal verkauft werden soll. Da macht man mal eine Abschätzung wie viel Rechenleistung gebraucht wird und kommt nach Jahren dann doch an die Grenzen, weil es ständig neue Ideen und Wünsche gibt. Da kommen durchaus Überlegungen auf mit Assembler das letzte rauszuholen, wohl dem der jemand hat, der das kann. Deshalb gehört das in der technischen Informatik auch zu den Basics.



  • @Ethon
    Aber nur ausnahmsweise und zum Trost 😉

    Siehst du, hier ist auch wieder einer, der Vorurteile über Assembler verbreitet, weil er nichts oder nur wenig weiß:

    Wurst schrieb:

    Ich finde den Vergleich von Assembler und anderen Hoch-Sprachen ziemlich witzlos.

    Verschiedene Sprachen sind für unterschiedliche Dinge gut, und je besser man den Unterschied kennt, desto sinnvoller kann man unterschiedliche Sprachen einsetzen. Aber man kann nicht alles über alle Sprachen wissen und je besser man in Sprache X ist, desto weniger (oder mehr, je nachdem) braucht man eine andere Sprache, weiß aber gleichzeitig um so besser, für welchen Einsatzzweck X nicht optimal ist.

    Wurst schrieb:

    Als Mensch, z.B. das Intel-Compiler-Optimizer-Team, hat man theoretisch immer die Möglichkeit die CPU besser auszunutzen als ein Optimizer, da man Sinn und Ziel vom Code kennt.

    Das Intel-Compiler-Optimizer-Team hat auch nicht die Weisheit mit Löffeln gefressen, wenn es z.B. um Parallelperformance geht. Bei Multicores(z.B. mehr als 16) dürfte es sogar recht schwierig und mühsam sein, die etwa Verzahnung der Befehlsketten von Hand einzustellen. Aber das Intel-Optimizer-Team hat Werkzeuge zum Optimieren, wie Profiler und Thread-Debugger und Optimierzeugs usw., die auch jeder andere nutzen kann, um seinen Code zu optimieren und schnelle Compiler und Libs, die auch jeder (zumindest zahlend) sich zu nutze machen kann. Wenn alle Welt vor Asm davonläuft, ist es natürlich um so leichter, mit Optimierungen jenseits der Algorithmenebene auf den Markt zu kommen. Übung und Know How ist der springende Punkt, nicht das Vorurteil

    Wurst schrieb:

    Kein Mensch kommt aber auf die Idee für den PC (Win,Linux,...) eine Applikation in Assembler zu entwickeln.

    Das ist auch schon wieder falsch, und das kann auch nur einer schreiben, dem die Möglichkeiten neuerer Assembler überhaupt nicht bekannt sind, geschweige denn, sie zu nutzen weiß.
    Assembler wie fasm ( http://www.flatassembler.net/ )
    oder RosAsm oder Betriebsysteme wie MenuetOS ( http://menuetos.net/ ) oder Linker wie http://www.digitalmars.com/ctg/optlink.html wurden z.B. in Assembler entwickelt. In Linux gibt es das beliebte Programm Midnight Commander (siehe dazu http://www.softpanorama.org/OFM/Paradigm/Ch04/mc.shtml).
    Das Original, der Norton Commander wurde in reinem und recht einfachem Assembler entwickelt. Der MC selbst wurde nicht in Assembler gecodet daher auch
    etwas viel Hickack, das Ding für Linux umzusetzen. Letztlich: Es ist ein ursprünglich mit Assembler entwickeltes Tool, welches sich dieser Beliebtheit(durchaus noch immer) in der Linuxwelt erfreut.

    Wurst schrieb:

    Anders sieht das in der Industrie aus, wenn eine selbstentwickelte Hardware, mit irgendeiner CPU/GPU/DSP,..., womöglich ohne eigenes Betriebsystem, zigtausendmal verkauft werden soll. Da macht man mal eine Abschätzung wie viel Rechenleistung gebraucht wird und kommt nach Jahren dann doch an die Grenzen, weil es ständig neue Ideen und Wünsche gibt. Da kommen durchaus Überlegungen auf mit Assembler das letzte rauszuholen..

    Auch viel zu allgemein und eher daneben. In der Industrie zählt vor allem, was wirtschaftlich ist, und da kommt es meist auf den Einzelfall an, was jetzt wo wie eingesetzt wird. In gewisserweise haben dort alle Sprachen ihre Berechtigung, also nicht unbedingt das passende Argument für oder gegen irgendeine Sprache.



  • Hostfreak schrieb:

    Stell Dir mal vor in einer Grossbank werden täglich - sagen wir 40 Millionen Datenbankzugriffe (und das ist eher sehr wenig) gemacht. Man kann sich dann recht leicht vorstellen, wie sich jeder unnötige Zyklus der CPU geradezu potenziert. Bei solchen Programmen, die einerseits "transaktionssicher" - andererseits bei jeder Transaktion aufgerufen werden, ist absolute Effizienz das erste Gebot. Man kann zwar mit gewissen Hochsprachen sehr effizient programmieren - C++ oder Java und sonst so überladenen Programmiersprachen haben dort aber nichts verloren...

    Ich kenne da einen der bei einer Bank genau in dem Bereich arbeitet. Laut seiner Aussage werden alle Transaktionen in Sp´s umgesetzt. Andere Programmierung erfolgt wenn dann in Java oder vergleichbar abstrahierten Sprachen. Sicherheit geht da ganz klar über Performance, zumal da diverse unterschiedliche Systeme eingesetzt werden.

    ASM würde mich informell interesieren, um damit zu arbeiten muß man glaub ich ziemlich freaky sein. Bzw man muß nicht allss können, ein kleiner Einblick reicht aber.



  • Ich würd gern ein paar Details ergänzen.

    Einmal zu OPTLINK. Es stimmt, das Ding war tatsächlich vollständig in Assembler geschrieben. Aus verschiedenen Gründen hat Walter Bright aber entschieden, OPTLINK zumindest langfristig nach C zu portieren. (Damit niemand durcheinanderkommt: Ursprünglich stammt OPTLINK im Wesentlichen von Steve Russell; benutzt wurde er dann innerhalb des C++-Compilers "Zortech C++" -> "Symantec C++" -> "DigitalMars". Dieser Compiler stammt von Walter Bright. Walter Bright beschäftigt sich also mit "fremdem", hochoptimiertem Assembler-Code, der somit natürlich ziemlich schwer zu verstehen ist.)
    Seine Bemühungen hat er hier dokumentiert: http://drdobbs.com/blogs/architecture-and-design/228701319

    Dann zum "optimierenden Assembler": Man kann das sinnlos finden (braucht hier sicherlich auch nicht diskutiert zu werden), aber interessehalber: Randall Hyde, der den HLA (High-Level Assembler) entwickelt, plant für zukünftige Versionen einen Optimierer. Hinweise und Andeutungen in diese Richtung:

    http://homepage.mac.com/randyhyde/webster.cs.ucr.edu/HighLevelAsm/HLADoc/HLARef/HLARef_html/HLAReference.htm (HLA Reference Manual)
    "Unlike various HLL compilers, HLA does not (yet!) attempt to optimize the code that you write."

    http://homepage.mac.com/randyhyde/webster.cs.ucr.edu/HighLevelAsm/hla3/0_hla2.html (HLA v3.0 Preview and Source Code)
    "If you're interested in working on the HLA project, here are some suggestions and areas where I expect I'll need some help: ... F. Work on optimizers for HLA. ..."

    http://webster.cs.ucr.edu/AsmTools/HLA/HLADoc/HTMLDoc/hlafaq.txt (HLA FAQ)
    "17: q. MASM has a nasty habit of changing instructions behind your back. HLA also seems to have this same problem."

    Vielleicht ist diese "schlechte Angewohnheit" von MASM schon ein Zeichen für Optimierungsversuche von MASM? Und dann heißt es in der Antwort u.a.:

    "In general, I have plans of adding a data flow analyzer and an optimizer around version three of HLA. While I certainly intend to provide source level control of the optimizer, if you are offended by an assembler that plays with your source code, then HLA is not for you. On the other hand, if you would like to be able to write readable code and leave it up to the compiler to deal with instruction scheduling and peep-hole optimizations, HLA will be a big win."



  • masm schrieb:

    dot schrieb:

    masm schrieb:

    Die Größe ist heut zu tage nur noch in wenigen Fällen von Bedeutung.

    Ist das so? Ich würde mal behaupten, die Größe ist vor allem heutzutage immer mehr von Bedeutung. Denn die CPUs werden immer schneller, die Speicher aber nicht. Google mal nach Instruction Cache...

    Der (code-) cache ist stetig mit den CPU Generationen gewachsen und, gemäß sein Natur, auch sein Geschwindigkeit. Auser in sehr kleine Schleifen (<= 32Byte), machte meiner Erfahrung nach die Befehlsgröße keinen Unterschied mehr.

    Ich denke das der Cache(Code+Daten) auf 64Bit-x86 gerne noch etwas grösser sein sollte, weil im 64 Bit-Mode der Cache sich um ein vielfaches schneller füllt als im 16/32 Bit-Mode und deren kleineren Adressen und Register+Werte.

    Typisches Beispiel: add eax,1 und inc eax ... wenn man nicht grade für den Pentium 4 programmiert, ist reine Geschmackssache – einen Geschwindigkeitsunterscheide habe ich in (sinnvollen) Algorithmen noch nie festgestellt (genau wie bei XOR vs. MOV).

    Verwendet man in einem Code das EAX-Register und möchte danach das AX-Register mit einem Wert beschreiben, dann ist es sinnvoll das EAX-Register mit "xor eax,eax" zu löschen, noch bevor man ein Wert nach AX schreibt.

    ...

    Es gibt verschiedene Möglichkeiten zur Optimierung.
    Von sehr grosser Bedeutung ist es darauf zu achten, dass Speicherzugriffe nach Möglichkeit richtig ausgerichtet sind. D.h. WORD-Zugriffe sollten auf gerade Adressen erfolgen welche durch 2 teilbar sind und DWORD-Zugriffe auf Adressen die durch 4 teilbar sind usw..

    ...

    Wenn man ein Register beschreibt und unmittelbar danach auf das selbe Register ein Lesezugriff erfolgt, dann gibt es eine Verzögerung, weil sich so eine Kombination nur schlecht paralell ausführen läßt. (Der XOR-Befehl macht hier eine Ausnahme.)
    (Die Intel Core2-Architektur kann beispielsweise 4 Integer-Befehle paralell ausführen. Und das Register-renaming und das Zerlegen in Micro-Ops hat auch seine Grenzen.)
    Je nachdem wie viele Befehle gleichzeitig von der jeweiligen CPU abgearbeitet werden können und wieviele Teilstufen dabei intern von der CPU benutzt werden bis ein Befehl vollständig ausgeführt wird und welche Abhängigkeiten zwischgen den Befehlen bestehen, desto großer sollte der Abstand zwischen jenen Befehlen sein welche in einer Register-Abhängigkeit stehen.

    ...

    Anstelle von "add, eax, 1", oder "inc eax" könnte man auch ein "lea eax, [eax+1]" verwenden. Wenn noch weitere Register, oder Werte hinzuaddiert, oder ein Register mit 2,4, oder 8 multipliziert werden soll, dann bringt der einzelne LEA-Befehl noch mehr Vorteile gegenüber mehrerer anderer Befehle.

    ...

    Anstelle von einer Kombination aus push/pop-Befehlen kann man auch mov/mov-Befehle verwenden. Ein Pentium 4 verarbeitet pop/push-Befehle schneller als mov/mov-Befehle, andere CPUs verarbeiten mov/mov-Befehle schneller als push/pop-Befehle.
    Jeder der es möchte kann es auf seiner eigenen CPU gerne einmal ausprobieren und es selber messen, ob die Kombination aus push/pop, oder die Kombination aus mov/mov schneller abgearbeitet wird.
    Zu diesem Zweck hat "Frank Kotler" eine entsprechende Testroutine(für Linux und NASM) geschrieben:
    https://groups.google.com/group/alt.lang.asm/browse_thread/thread/3d4fefc9bcd80b87/de738e9275a9abc7?hl=de&lnk=gst&q=pushvsmov#de738e9275a9abc7
    Etwas abgewandelt läßt sich dieses Beispiel auch für rinige andere Codeoptimierungen verwenden.

    Neben den Anleitungen von Intel und AMD worin jeweils die Optimierung deren CPU-Modelle relativ anschaulich mit Beispielen erläutert wird habe ich auf die mal gesucht und etwas darüber gefunden:
    Assembly Optimization Tips by Mark Larson
    http://www.mark.masmcode.com/

    Dirk Wolfgang Glomp



  • Passt zwar nur begrenzt zum Kontext hier, aber ich fand es witzig mal ein Notepad in Assembler zu sehen. Die Größe der EXE ist 5632 Bytes.

    ; Simple text editor - fasm example program
    
    format PE GUI 4.0
    entry start
    
    include 'win32a.inc'
    
    IDM_NEW   = 101
    IDM_EXIT  = 102
    IDM_ABOUT = 901
    
    section '.text' code readable executable
    
      start:
    
            invoke  GetModuleHandle,0
            mov     [wc.hInstance],eax
            invoke  LoadIcon,eax,17
            mov     [wc.hIcon],eax
            invoke  LoadCursor,0,IDC_ARROW
            mov     [wc.hCursor],eax
            invoke  RegisterClass,wc
            test    eax,eax
            jz      error
    
            invoke  LoadMenu,[wc.hInstance],37
            invoke  CreateWindowEx,0,_class,_title,WS_VISIBLE+WS_OVERLAPPEDWINDOW,144,128,256,256,NULL,eax,[wc.hInstance],NULL
            test    eax,eax
            jz      error
    
      msg_loop:
            invoke  GetMessage,msg,NULL,0,0
            cmp     eax,1
            jb      end_loop
            jne     msg_loop
            invoke  TranslateMessage,msg
            invoke  DispatchMessage,msg
            jmp     msg_loop
    
      error:
            invoke  MessageBox,NULL,_error,NULL,MB_ICONERROR+MB_OK
    
      end_loop:
            invoke  ExitProcess,[msg.wParam]
    
    proc WindowProc hwnd,wmsg,wparam,lparam
            push    ebx esi edi
            cmp     [wmsg],WM_CREATE
            je      .wmcreate
            cmp     [wmsg],WM_SIZE
            je      .wmsize
            cmp     [wmsg],WM_SETFOCUS
            je      .wmsetfocus
            cmp     [wmsg],WM_COMMAND
            je      .wmcommand
            cmp     [wmsg],WM_DESTROY
            je      .wmdestroy
      .defwndproc:
            invoke  DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
            jmp     .finish
      .wmcreate:
            invoke  GetClientRect,[hwnd],client
            invoke  CreateWindowEx,WS_EX_CLIENTEDGE,_edit,0,WS_VISIBLE+WS_CHILD+WS_HSCROLL+WS_VSCROLL+ES_AUTOHSCROLL+ES_AUTOVSCROLL+ES_MULTILINE,[client.left],[client.top],[client.right],[client.bottom],[hwnd],0,[wc.hInstance],NULL
            or      eax,eax
            jz      .failed
            mov     [edithwnd],eax
            invoke  CreateFont,16,0,0,0,0,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_RASTER_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FIXED_PITCH+FF_DONTCARE,NULL
            or      eax,eax
            jz      .failed
            mov     [editfont],eax
            invoke  SendMessage,[edithwnd],WM_SETFONT,eax,FALSE
            xor     eax,eax
            jmp     .finish
          .failed:
            or      eax,-1
            jmp     .finish
      .wmsize:
            invoke  GetClientRect,[hwnd],client
            invoke  MoveWindow,[edithwnd],[client.left],[client.top],[client.right],[client.bottom],TRUE
            xor     eax,eax
            jmp     .finish
      .wmsetfocus:
            invoke  SetFocus,[edithwnd]
            xor     eax,eax
            jmp     .finish
      .wmcommand:
            mov     eax,[wparam]
            and     eax,0FFFFh
            cmp     eax,IDM_NEW
            je      .new
            cmp     eax,IDM_ABOUT
            je      .about
            cmp     eax,IDM_EXIT
            je      .wmdestroy
            jmp     .defwndproc
          .new:
            invoke  SendMessage,[edithwnd],WM_SETTEXT,0,0
            jmp     .finish
          .about:
            invoke  MessageBox,[hwnd],_about_text,_about_title,MB_OK
            jmp     .finish
      .wmdestroy:
            invoke  DeleteObject,[editfont]
            invoke  PostQuitMessage,0
            xor     eax,eax
      .finish:
            pop     edi esi ebx
            ret
    endp
    
    section '.data' data readable writeable
    
      _title TCHAR 'MiniPad',0
      _about_title TCHAR 'About MiniPad',0
      _about_text TCHAR 'This is Win32 example program created with flat assembler.',0
      _error TCHAR 'Startup failed.',0
    
      _class TCHAR 'MINIPAD32',0
      _edit TCHAR 'EDIT',0
    
      wc WNDCLASS 0,WindowProc,0,0,NULL,NULL,NULL,COLOR_BTNFACE+1,NULL,_class
    
      edithwnd dd ?
      editfont dd ?
    
      msg MSG
      client RECT
    
    section '.idata' import data readable writeable
    
      library kernel,'KERNEL32.DLL',\
              user,'USER32.DLL',\
              gdi,'GDI32.DLL'
    
      import kernel,\
             GetModuleHandle,'GetModuleHandleA',\
             ExitProcess,'ExitProcess'
    
      import user,\
             RegisterClass,'RegisterClassA',\
             CreateWindowEx,'CreateWindowExA',\
             DefWindowProc,'DefWindowProcA',\
             SetWindowLong,'SetWindowLongA',\
             RedrawWindow,'RedrawWindow',\
             GetMessage,'GetMessageA',\
             TranslateMessage,'TranslateMessage',\
             DispatchMessage,'DispatchMessageA',\
             SendMessage,'SendMessageA',\
             LoadCursor,'LoadCursorA',\
             LoadIcon,'LoadIconA',\
             LoadMenu,'LoadMenuA',\
             GetClientRect,'GetClientRect',\
             MoveWindow,'MoveWindow',\
             SetFocus,'SetFocus',\
             MessageBox,'MessageBoxA',\
             PostQuitMessage,'PostQuitMessage'
    
      import gdi,\
             CreateFont,'CreateFontA',\
             DeleteObject,'DeleteObject'
    
    section '.rsrc' resource data readable
    
      ; resource directory
    
      directory RT_MENU,menus,\
                RT_ICON,icons,\
                RT_GROUP_ICON,group_icons,\
                RT_VERSION,versions
    
      ; resource subdirectories
    
      resource menus,\
               37,LANG_ENGLISH+SUBLANG_DEFAULT,main_menu
    
      resource icons,\
               1,LANG_NEUTRAL,icon_data
    
      resource group_icons,\
               17,LANG_NEUTRAL,main_icon
    
      resource versions,\
               1,LANG_NEUTRAL,version
    
      menu main_menu
           menuitem '&File',0,MFR_POPUP
                    menuitem '&New',IDM_NEW
                    menuseparator
                    menuitem 'E&xit',IDM_EXIT,MFR_END
           menuitem '&Help',0,MFR_POPUP + MFR_END
                    menuitem '&About...',IDM_ABOUT,MFR_END
    
      icon main_icon,icon_data,'minipad.ico'
    
      versioninfo version,VOS__WINDOWS32,VFT_APP,VFT2_UNKNOWN,LANG_ENGLISH+SUBLANG_DEFAULT,0,\
                  'FileDescription','MiniPad - example program',\
                  'LegalCopyright','No rights reserved.',\
                  'FileVersion','1.0',\
                  'ProductVersion','1.0',\
                  'OriginalFilename','MINIPAD.EXE'
    

Anmelden zum Antworten