home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / PROG_PAS / TVTOYS.ZIP / TIP.TXT < prev    next >
Text File  |  1994-01-03  |  11KB  |  374 lines

  1.  
  2.   TIP.TXT
  3.  
  4.   TVToys extra
  5.   PJB 1993, Internet mail to d91-pbr@nada.kth.se
  6.   PJB 1993, CompuServe mail to INTERNET:d91-pbr@nada.kth.se
  7.  
  8.  
  9. Here are some general ideas that might and might not be
  10. of interest to you.
  11.  
  12. -----
  13.  
  14. Do you have problems with SmartDrive not saving your programs before
  15. they crash your computer? Try adding this code snippet before
  16. MyApp.Init and SmartDrv will flush (write) its contents before your
  17. program starts. You might want to enclose it with {$IFDEF Debug}
  18. or something similar.
  19.  
  20.   (* Flush SmartDrive disk cache, equivalent to "smartdrv /c" *)
  21.   asm
  22.     mov ax,4A10h
  23.     mov bx,1
  24.     int 2Fh
  25.   end;
  26.  
  27.  
  28. (This is now a function in toyUtils called FlushSmartDrive)
  29.  
  30. -----
  31.  
  32. Do you want your program to retain the startup video mode even if
  33. it is not recognized by Turbo Vision, like extended video modes?
  34.  
  35. Try this to keep the startup video mode active:
  36.  
  37.   begin
  38.     if IsProbablyTextMode then
  39.       PreventModeSwitch;
  40.     MyApp.Init;
  41.     MyApp.Run;
  42.     MyApp.Done;
  43.   end.
  44.  
  45. The PreventModeSwitch makes Turbo Vision "forget" about resetting the
  46. video mode to 2, 3 or 7. Use PreventModeSwitch before every call to
  47. InitVideo (called by TApplication.Init and DosShell etc) to make Turbo
  48. Vision accept the current video mode.
  49.  
  50. You can also put the if statement in your application's Init,
  51. just make sure it executes before the inherited Init, like this:
  52.  
  53.   constructor MyApp.Init;
  54.   begin
  55.     if IsProbablyTextMode then
  56.       PreventModeSwitch;
  57.     inherited Init;
  58.   end;
  59.  
  60. See also: RESTEST.PAS
  61.  
  62.  
  63. -----
  64.  
  65. Are you short of memory and don't use the Tile/Cascade commands?
  66. Make your MyApp.HandleEvent inherit TProgram's HandleEvent, not
  67. TApplication's. That is, change your MyApp.HandleEvent's
  68.  
  69.   inherited HandleEvent(Event);
  70.  
  71. into
  72.  
  73.   TProgram.HandleEvent(Event);
  74.  
  75. TApplication also responds to cmDosShell, so you need to respond to
  76. that yourself.
  77.  
  78. This makes your EXE file 2K (1940 bytes) smaller.
  79.  
  80.  
  81. -----
  82.  
  83. Are you still short of memory? If you change HelpFile's TStreamRecs
  84. so that neither has a Store you save 1.5K in TP6, but only 600 bytes
  85. in BP7. Check out the Patch lines below.
  86. Remember that you can't recompile TVHC without the Stores,
  87. (well... you can, but TVHC won't work) so keep a copy of the original
  88. HelpFile.
  89.  
  90.  
  91.   RHelpTopic: TStreamRec = (
  92.      ObjType: 10000;
  93.      VmtLink: Ofs(TypeOf(THelpTopic)^);
  94.      Load:    @THelpTopic.Load;
  95.      Store:   Nil                         {Patch}
  96.   );
  97.   RHelpIndex: TStreamRec = (
  98.      ObjType: 10001;
  99.      VmtLink: Ofs(TypeOf(THelpIndex)^);
  100.      Load:    @THelpIndex.Load;
  101.      Store:   Nil                         {Patch}
  102.   );
  103.  
  104.  
  105. -----
  106.  
  107. Here are my favourite time saving BP IDE macros.
  108. Please note that undoing the effects of any of these macros can
  109. be very unreliable. Undo works better if you select group undo, I think.
  110.  
  111.  
  112.   (* This macro inserts "begin", a blank line, "end" and positions
  113.      the cursor on the blank line *)
  114.  
  115.   MACRO PutBeginEnd
  116.     InsertText("begin\nend;");
  117.     CursorUp;
  118.     RightOfLine;
  119.     InsertText("\n  ");
  120.   END;
  121.  
  122.  
  123.   (* This macro just inserts "{$}" and puts the cursor inside *)
  124.  
  125.   MACRO PutDefine
  126.     InsertText("{$}");
  127.     CursorLeft;
  128.   END;
  129.  
  130.  
  131.   (* HERE IS A LIFE SAVER: it encloses the currently marked block with
  132.      "begin" and "end" keywords. You can do something similar for
  133.      {IFDEF} {ENDIF} and comments maybe *)
  134.  
  135.   MACRO MakeBlock
  136.     MoveToBlockBeg;
  137.     CursorUp;
  138.     RightOfLine;
  139.     InsertText("\n");
  140.     InsertText("begin\nend;");
  141.     LeftOfLine;
  142.     MoveBlock;
  143.  
  144.     MoveToBlockEnd;
  145.   END;
  146.  
  147.  
  148.   (* Here is a macro that produces button like shadows for use in help
  149.      files. To use it, type a header and execute the macro on the same
  150.      line. The current line is indented, a "▄" is appended and the next
  151.      line is completely overwritten with a shadow. If you change the
  152.      header, just delete the trailing "▄" and reexecute the macro.
  153.  
  154.   MACRO MakeHelpShadow
  155.     CursorDown;
  156.     LeftOfLine;
  157.     InsertText("  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀");
  158.     LeftOfLine;
  159.     CursorUp;
  160.     InsertText(" ");
  161.     LeftOfLine;
  162.     DeleteWord;
  163.     InsertText("    ");
  164.     RightOfLine;
  165.     InsertText("  ▄");
  166.     CursorDown;
  167.     DeleteToEol;
  168.   END;
  169.  
  170.  
  171.   (* I find that I use this command all the time, along with its move
  172.      companion. It copies a block but it places the cursor AFTER the
  173.      block, not before. Saves me A LOT of typing, now if I only could
  174.      figure out where to put the clipboard equivalent... *)
  175.  
  176.   MACRO CopyMoveAfter
  177.     CopyBlock;
  178.     MoveToBlockEnd;
  179.   END;
  180.  
  181. -----
  182.  
  183. If you have a word wrapping text editor, you can install it as a tool in
  184. BP (!) to do word wrap or other tasks that BP doesn't handle. The $LINE
  185. macro is especially useful if only your editor supports it!
  186.  
  187.   Here is a QEdit tool's command line:
  188.  
  189.     $SAVE ALL $EDNAME -n$LINE
  190.  
  191. -----
  192.  
  193. Have you dreamed about ForEach style procedure calls? Don't like
  194. assembler? Here is one way to do it.
  195.  
  196. Let's implement TCollection.ForEach as a demonstration.
  197.  
  198. Here is what you need:
  199.  
  200.     (*******************************************************************
  201.       Below is a small system to call local procedures without
  202.       resorting to assembler.
  203.     *******************************************************************)
  204.     procedure DoNothing; far; assembler; asm end;
  205.  
  206.     const
  207.       PushParameters : pointer = @DoNothing;
  208.  
  209.     type
  210.       JumpToProc = procedure;
  211.  
  212.     {$IFDEF Windows}
  213.       procedure PushPreviousBP; inline($8B/$46/$00/$24/$FE/$50);
  214.         (* MOV  AX,[BP]
  215.            AND  AL,0FEh
  216.            PUSH AX *)
  217.     {$ELSE}
  218.       procedure PushPreviousBP; inline($FF/$76/$00); (* PUSH WORD PTR [BP] *)
  219.     {$ENDIF}
  220.  
  221.  
  222. (*  You then need a procedural-type:  *)
  223.  
  224.     type
  225.       ActionProc = procedure (P:Pointer);
  226.  
  227.     (*******************************************************************
  228.     *******************************************************************)
  229.  
  230.     procedure TCollection.ForEach(Action:Pointer);
  231.       var
  232.         I : integer;
  233.     begin
  234.       for I:=0 to Count-1 do
  235.       begin
  236.         (* What we want to do:   Action(Items^[I])
  237.            where Action is a pointer to a far procedure of the same
  238.            type as ActionProc.
  239.            The problem is that ActionProc(Action)(Items^[I])
  240.            doesn't set up the stack properly since we're calling
  241.            a LOCAL procedure *)
  242.  
  243.         (* 1) First push the parameters: Simulate a call to an AddModeProc
  244.            while really calling a RETF, thus leaving the parameters on
  245.            the stack *)
  246.         ActionProc(PushParameters) (Items^[I]);
  247.  
  248.         (* 2) Push the previous BP to set up the stack properly *)
  249.         PushPreviousBP;
  250.  
  251.         (* 3) Call the procedure: JumpToProc is just a type cast to make
  252.            the compiler think that Action takes no parameters *)
  253.         JumpToProc(Action);
  254.       end;
  255.     end;
  256.  
  257.     (*******************************************************************
  258.     *******************************************************************)
  259.  
  260. Assembler speaking, this is almost what happens:
  261.  
  262.     asm
  263.       (* 1 *)
  264.       LES  DI,Items^[I]            (* Pseudo *)
  265.       PUSH ES
  266.       PUSH DI
  267.  
  268.       {Meaningless DoNothing funtion call removed}
  269.  
  270.       (* 2 *)
  271.       PUSH WORD PTR [BP]
  272.  
  273.       (* 3 *)
  274.       CALL FAR Action
  275.     end;
  276.  
  277.  
  278. -----
  279.  
  280.   Here is what ScanEVGAModes in VIDEO.PAS used to look like
  281.  
  282.   (*******************************************************************
  283.     procedure ScanVideoModes(First:Byte; AddMode:Pointer);
  284.       First:   First video mode to try
  285.       AddMode: Procedure to call for each valid text video mode.
  286.  
  287.       ScanVideoModes attempts to find out what video modes are available.
  288.       It tries to set every video mode possible, checking to see if
  289.       the BIOS put valid data for a text mode in the BIOS data segment.
  290.       ScanVideoModes starts at mode First and works its way up to mode
  291.       127. Every time a valid Text video mode is found, AddMode is called.
  292.       AddMode should be a FAR procedure with the same parameters as an
  293.       AddModeProc.
  294.  
  295.       ■ ScanVideoModes behaves like ForEach (TGroup, TCollection)
  296.         in Turbo Vision. AddMode MUST be a local procedure
  297.         (a procedure inside another procedure) and since the
  298.         parameter has to be a pointer, no checks will be made
  299.         whatsoever on the parameter AddMode. Your program could
  300.         easily crash if you use the wrong kind of procedure.
  301.   *******************************************************************)
  302.   procedure ScanEVGAModes(First:byte; AddMode:AddModeProc);
  303.     var
  304.       Mode : byte;
  305.       Rows, Columns : byte;
  306.   begin
  307.     for Mode:=First to 127 do
  308.       if (Mode<>$0B) and (Mode<>$0C) then (* Skip reserved internal modes *)
  309.       begin
  310.         SetMode(Mode or $80);
  311.         NoRefresh;
  312.  
  313.         Rows:=Mem[Seg0040:CrtRows]+1;
  314.         Columns:=Mem[Seg0040:CrtWidth];
  315.         if (Mode=GetMode and $7F) and IsProbablyTextMode then
  316.         begin
  317.           (* First push the parameters: Simulate a call to an AddModeProc
  318.              while really calling a RETF, thus leaving the parameters on
  319.              the stack *)
  320.           AddModeProc(PushParameters)
  321.             (Mode, Rows, Columns, Mem[Seg0040:CrtPoints], IsColorMode);
  322.           (* Push the previous BP to set up the stack properly *)
  323.           PushPreviousBP;
  324.           (* Call the procedure: JumpToProc is just a type cast to make
  325.              the compiler think that AddMode takes no parameters *)
  326.           JumpToProc(AddMode);
  327.         end;
  328.       end;
  329.     end;
  330.  
  331. -----
  332.  
  333. Here is a very different way to call local procedures (see above):
  334. I find it less intuitive.
  335.  
  336.  
  337.   (* NewActionProc corresponds to ActionProc above. Here, Action
  338.      MUST be the last parameter for CallLocalProc to work. *)
  339.   type
  340.     NewActionProc = procedure (P:Pointer; Action:Pointer);
  341.  
  342.   procedure __CallLocalProc; far; assembler;
  343.   asm
  344.     POP  AX
  345.     POP  BX
  346.     POP  CX
  347.     POP  DX
  348.  
  349.     {$IFDEF Windows}
  350.     MOV  AX,[BP]
  351.     AND  AL,0FEH
  352.     PUSH AX
  353.     {$ELSE}
  354.     PUSH [BP].WORD
  355.     {$ENDIF}
  356.  
  357.     PUSH BX
  358.     PUSH AX
  359.     PUSH DX
  360.     PUSH CX
  361.   end;
  362.  
  363.   const
  364.     CallLocalProc : procedure = __CallLocalProc;
  365.  
  366.   procedure TCollection.ForEach(Action:Pointer);
  367.     var
  368.       I : integer;
  369.   begin
  370.     for I:=0 to Count-1 do
  371.       NewActionProc(CallLocalProc) (Items^[I], Action);
  372.   end;
  373.  
  374.