|
|||||||
![]() |
![]() |
||||||
|
|||||||
|
常见问题 Win32Forth FAQ本文完全应该为更多的“常见”问题而重新编写,有些问题已经不再相关或者正确,使用时请自留意。 许多例子文件都用“ only forth also definitions”开始。我想应该有一个古老的与之相关的字“forget”,我从哪里可以得到这些字的解释?您应该看 ANS documentation 关于字汇表的细节。请使用 Forth 控制台的 Help 帮助菜单。其中有一个项目供您阅读 ANS 文档。 WinDemo 包含一个 Windemo.bmp文件, 它实现了工具栏。有从头开始构造一个工具栏的工具吗?没有特殊的工具,我使用 Windows Paint 编辑它们。我建议您复制文件 WINDEMO.BMP 并更名,然后在您的应用程序中包含这个新的名字用作工具栏。 我相信我找到一个分析流程。如果您在输入一个十进制的时候输入了一个包含有单一字母 'd' 或者 'e', 的数,系统并不标示也这个字没有找到。Win32Forth 只是返回OK,并没有在堆栈上留下任何东西。正确。单独使用字母 'd' 和 'e' , 或者在一个合法的数字中,不产生错误。这是浮点数,使用 IEEE 浮点格式。如果您使用浮点堆栈显示字“ F.S ”,就会看到这个数被留在浮点堆栈上。 我如何调试对象和类中的字? Mdebug 只能在方法上工作。我如何使用debug 或者 mdebug来调试 WM_COMMAND和 WM_TIMER 这样的方法,谢谢!有一个称为 BREAKER 的空定义: : BREAKER NOOP ; 如果您这样使用: :M WM_TIMER ( --- ) BREAKER ....the definition of WM_TIMER.... ;M 在运行您的程序之前输入以下的 Forth 命令行: DEBUG BREAKER 则 Forth 在遇到 BREAKER 中的断点时将启动调试器。接着使用 'U' 调试上面定义的 WM_TIMER 。可能不优雅,但是还能工作。 尽管我能够很好地使用 "methods" 和"ivars",但是不能使"privates" 工作。我缺少了什么?我几乎看了所有的可用文档。使用“ int ”创建的实例变量都是 private (私有) 的,直到我加入了允许访问它们的点语法。所以我建议现在不应该有 privates (私有的)变量。它们已经是局部的,因为您可以在多个类和对象中定义多个同名的变量。 我花了很多时间试图理解在 Win32forth使用对象技术的原理,研究了许多例子,如果我做一些小的改变则可以成功,但是在进行像应答MouseMove回调函数以显示坐标这样的事情时(这是一个C++书上的例子)却没有成功。我不能说明全部的概念。 HELLO.f的全部case语句隐藏在WINHELLO.f的什么地方?这个问题在你们听来可能很愚蠢,但我认为我要是弄清楚几个关键点后就会解决问题的。的确有几个不能理解的关键点。 Andrew 的例子 (HELLO.F) 没有使用类实现,所以每件事情都得辛苦地编码。 另一方面, WINHELLO.F 使用 WINDOW 类实现,它将自动扫描 HelloWindow 类和对象以查找用 WM_ 为前缀定义的窗口消息,并在 WINCON 字汇表中查找。然后这些常量就被作为窗口消息对待,如果接收到了这类消息,就会把它传递给适当的 WM_ 方法。没有定义的方法就通过默认的窗口消息处理器来处理。 这是从 WINDOW.F 中摘取的一段, (WndProc) 是窗口回调函数,只要窗口想发送一个消息给 Win32Forth 窗口,它就会被调用一次。这个定义的第一部分涉及创建窗口的特殊情况。我没有完全理解其中的细节,所以不能向您解释。 : (WndProc) ( hwnd msg wparam lparam -- res ) [ also classes ] GWL_USERDATA 4 pick Call GetWindowLong ( object address ) ?dup 0= if 2 pick WM_CREATE <> if DefaultWindowProc exit then dup abs>rel @ \ window object pointer from \ first cell of CREATEPARMS 4 pick ( obj hwnd ) 2dup GWL_USERDATA swap Call SetWindowLong drop \ save pointer over ! \ set hWnd parameter of window struc then 这里我们来看我们定义的窗口消息。如果它不是已经定义的,则控制被传递给“ DefWindowProc: [[ ]] ”,它允许用户在需要的时候为每个新窗口定义一个新的默认窗口处理过程。如果 WM_ 消息已经定义,它将被“ catch ”执行并且如果回调没有发生错误,回调将返回到窗口。 3 pick ( msg ) over >class MFA ((findm)) if sp0 @ >r sp@ 4 cells+ sp0 ! dup>r catch ?dup if r@ WndProcError then r>drop r> sp0 ! else \ -- a1 \ the object address DefWindowProc: [[ ( a1 -- ) ]] \ gets used here then [ previous ] ; ' (wndproc) WndProc TheWndProc DefWindowProc: 在这里定义,它允许任何窗口识别 WM_WIN32Forth 消息,只要这个消息已经定义。否则控制就传递给 "DefaultWindowProc" :M DefWindowProc: ( h m w l -- res ) 2 pick WM_WIN32Forth = if Win32Forth: [[ self ]] 0 else DefaultWindowProc then ;M 如果您不能完全理解这些,那也没有什么关系。我也有许多不理解之处。 Andrew 完成了全部的艰苦工作,并首次使它能够工作。您所需要知道的最基本的事情就是,如果您在一个窗口中定义了一个窗口消息(它使用 WM_ 开始),那么当 Windows 向您的窗口发送这个消息时,您的方法就会被调用。细节非常琐碎,但是 Win32Forth 的工作方式却覆盖了大部分的细节。 在帮助文件“开始”(通过 F1)中说, Forth 不是大小写敏感的。但是在“call GetStockObject”这样的调用中却必须按模板的要求输入??Win32Forth 是大小写不敏感的,但是使用 CALL 调用 Windows 过程时除外。过程名字将按您在源文件中输入的那样原封不动地传递,以便于正确访问外部的 DLL ,因为它们是大小写敏感的。 我试图从 Win32Forth的SciTech软件中运行 WinDirect DLL,没有成功。请问我如何能够在Win32Forth 中正确地使用DLL甚至实验 WinDirect?如果您运行的是 Win32Forth 3.0 或者更高的版本,您试图访问的 DLL 是 32 位的 DLL, 则您只需要像下面这样简单地加入 WinLibrary 语句就可以了: WinLibrary MYDLL.DLL 之后就可以在应用程序中调用 DLL 功能: CALL MyDllFunction 确保所有堆栈上的参数是逆序排列的,也就是说,最靠近字 CALL 的参数是 C 语言调用描述中出现的第一个参数。 注意: Win32Forth 为特别的函数名称查找所有的 DLL ,按最先找到的引用。如果您混淆了函数名,那可能会导致麻烦。 我试着在一个应用中运行两个窗口,每个都有自己的菜单条。可是每个窗口都试图使用最后装入的菜单定义。从 Win32Forth 版本 3.2 开始,每个窗口都有它自己的菜单。请参看示例程序 WINMULTI.F ,它解释了如何创建多窗口应用。 在这个 Forth系统中,有没有文档关于使用对象的<Super命令等等的细节或者其背后的哲学。我试验了几个例子,使我特别想通过Win32forth学习更多的面向对象程序设计的内容,我能够从命令行试验一些不同的方法,但是没有文档使我总觉得会少写了什么。是否能够使用Yerkes或者从Mac上得到一些面向对象的Forth文档?阅读 这里。 您可以得到使用 Win32Forth 进行面向对象编程的一些例子和简单的描述。 此外,因为 Andrew McKewan 把 NEON (Yerks/MOPS) 的面向对象编程模型移植到了 Win32Forth , MOPS 手册使用相似, OOP 概念也与 Win32Forth 中使用的相似。 我真的喜欢在不重新构造系统的情况下构造客客户定制的对话框,因为在 Visual C++中我做不到。版本 3.0 和更高的版本含有重写的控件代码,它至少可以创建对话框(真正的窗口建模)而不需要对话框编辑器,参看示例 WINDILOG.F 。 版本 6.08 以及更高的版本包含一个 GUI Form Designer, ForthForm,参见相关手册。 如果您使用 Win9x ,还可以使用 Michael Hillestr?m 的 DiaEdit ( 从这个网站上下载 对话框资源文件 ( .RES ) 可以在对话框编辑器中创建,这个编辑器包含在免费的 LCC 编译器中,从 这里下载 我在堆栈参数的清晰性方面发生了混淆。例如在 Window.f 源代码中有两个方法::M On_Init: ( -- ) ;M :M WM_CREATE ( h m w l -- res ) On_Init: [[ self ]] 0 ;M 为什么堆栈参数 hwnd msg wparam lparam在 On_Init: 方法中没有了?实际上,On_Init:, On_Size: 的堆栈参数在 Window.f, Windemo.f 和 WinEd.f中是不同的。在上面的例子中, "On_Init:" 是一个不做特别事情的方法,事实上它不做任何事情,只是占据了一个位置,以便于后面的 WM_CREATE 方法使用。所有的 Win32Forth WM_ 方法在 Windows 回调时被调用,我们这里的情况是当它需要发送一个窗口创建消息 (WM_CREATE) 时。当这种情况发生时, WM_CREATE 方法将调用 On_Init: 方法。双括号“ [[ self ]] ” 说明运行时间要求引用 On_Init:, 这样如果您重新定义了 On_Init:, 那么您定义的 On_Init: 将被引用,而不是上面没有显示的默认操作,这也就是一种为定义在 [[ self ]] 中的方法进行的自动重定义连接。 您的第二个问题与这样一个事实有关:堆栈好像留下一个奇怪的状态。是的,您是对的,在从 WM_CREATE 方法返回之前并没有清除堆栈,但那是不需要的。您看到了, WM 方法只是通过窗口回调引用,这意味着窗口调用 Forth ,在这个过程中,堆栈是为执行方法而创建的,它们在方法返回窗口时被破坏,所以并没有在窗口上留下不同的东西。每个 WM_ 方法在消息无错误地处理完成之后应用返回一个非零值。事实上,就算是在堆栈上留下一些额外的东西,也比堆栈下溢要好。 我们想把自己的工业控制产品(现在是用 F-PC编写的)转换到Windows中,您能说说把一个现有的应用转换到Win32Forth的可能困难吗-- 除了用户界面?很好,除了用户界面。 Forth 是更好的 Forth ,然而 Win32Forth 是一个线性寻址的 32 位 Forth ,而不是 F-PC 的 16 位方式,这通常会导致一般的 2+ 还是 4+ ( 或者 ANSI 的 CELL + ) 问题。在使用 Win32Forth 时的最大问题是 ANSI 的兼容性而不是 F-PC 的兼容性,所以文件字不同。 Win32Forth 也加入了完全的面向对象的支持 ( NEON 或者 MOPS) ,它提供对编程问题的全新的思考方法。 我应该提示您不论在 Windows 中还是在 F-PC 中,排除了用户界面,那可是放弃了应用程序的一大部分。 您还可能在 Win32Forth 中遇到其它的问题,比如访问硬件的问题。 Win32Forth 通过 Windows 操作系统访问硬件,所以硬件的访问能力极其有限,基本上您只能访问串行口和打印口。 我想在屏幕上得到一个 EDIT-WINDOWS 窗口。我不想通过编译源程序并用 POPUP创建。您能告诉实现这个要求的其它方法吗?Win32Forth 包含了几个示例程序,也就是这几个例子可用。注意 WINEDIT 确实弹出一个原始的建立在 Win32Forth 内部的编辑框,这在浏览模式下用于接收用户输入的最简单的文本。如果您仅是想得到简单的单个参数输入,您可以复制这个方法以避免创建您自己的窗口。 我想知道怎么能够得到 win32forth 控制台的颜色,并使用它改变以后打印字符串的颜色(不是像>BOLD 和>NORM 所做的那样改变整个屏幕的颜色)那是不可能的。您只能使用 FGBG! 来设置整个屏幕的前景色 / 背景色。 当然,您总是能够使用某些 Windows API 函数来设置控制台字体和类型,比如: Font vFont WinDC CurrentDC : texttest cls GETCOLROW gotoxy cr CONDC PutHandle: currentDC \ initialize DC to the console ltred SetTextColor: currentDC 10 Width: vFont 18 Height: vFont 0 Escapement: vFont Create: vFont s" Arial Black" SetFaceName: vFont \ default to Courier Handle: vFont SetFont: currentDC 120 160 ( x y ) s" Win32Forth " textout: currentDC 0 35 gotoxy ; texttest 但是每次控制台窗口收到了 WM_PAINT 消息(比如您改变了窗口的大小)后,您的输出窗口将消失,因为控制台的 WM_PAINT 处理器 ( 在 TERM.CPP 中定义)将用它自己的数据重新绘制窗口区域。 我试着使用 FOREGROUND 和 BACKGROUND (在 'COLOR.f'中定义)设置控制台窗口的前景和背景颜色,但是没有任何效果。FOREGROUND 和 BACKGROUND 并不在控制台窗口中工作。设置控制台窗口前景色和背景色的唯一方法是使用字 FGBG! ,比如: Color: red BG@ FGBG! \ set red foreground color FG@ Color: blue FGBG! \ set blue background color 为了与控制台窗口一同工作, FOREGROUND 和 BACKGROUND 应该改写为: : FG! { color_object -- } color_object ?ColorCheck drop Color: color_object BG@ FGBG! ; : BG! { color_object -- } color_object ?ColorCheck drop FG@ Color: color_object FGBG! ; 当您使用 view 一个字的同义词的时候,view 定位到一个错误的位置上例如,如果您 VIEW FLOAD ,它定位到 PRIMUTIL.F 的 59 行,那里 INCLUDE 被声明是 fload 的同义词。它应该定位到 fload 在源程序中的实际位置,也就是 KERNEL.F 的 4811 行。有时这不是一个大问题,特别是同义词与原来的工作差不了几行时,但它是一个 BUG 。 好的,它是一个问题,但是不可否认,它不是一个 BUG ,仅仅是 SYSNONYM 和 ALIAS 的工作方法。它们指向加阴影的字,字汇表并不能区别它们。 .. c" FLOAD" find .s [2] 5285076 -1 ok.. .. c" INCLUDE" find .s [2] 5285076 -1 ok.. 正如您所看到的,两种返回同样的项, VIEW INCLUDE 把您带到了同样的地方,但是这种情况是好的。有时这不是一个大问题,特别是同义词与原来的工作差不了几行,但它是一个 BUG 。 SELF 和 [ SELF ]在某些类中,我看到这样的内容: :M Foo: ;M :M Foo1: Foo: [ self ] ;M 谁能告诉我它们与下面有什么区别?:M Foo: ;M :M Foo2: Foo: self ;M
[ SELF ] 是后期绑定调用到 SELF 而 SELF 是早期绑定 :CLASS myclass <SUPER OBJECT :M Foo: ." Foo: from myclass" ;M :M Foo1: Foo: SELF ;M :M Foo2: Foo: [ SELF ] ;M ;CLASS :CLASS myclass2 <SUPER MYCLASS :M Foo: ." Foo: from myclass2" ;M ;CLASS myclass myobj1 myclass2 myobj2 对于同样 Foo1: 两者产生同样的信息,但是对 Foo2: 不同。因为 Foo2: myobj2 将找到 myclass2 中的第二个 Foo: ,而 Foo1: 是在编译时被绑定到原始的 Foo: 。 Foo: [ self ] 表示法用于强制的后期绑定,所以对于这个例子来说,如果您在一个子类中重新定义了一个新方法 Foo: ,那么它将替代原始的 Foo:, 但是只在您进行了后期绑定(运行时绑定)的时候。 这对于前向引用和重新定义非常方便,按您描述的方法使用,通过使用 self ,一个特定的方法并不需要在类被创建的时候就具有全部的功能。 如何在汇编器中调用 Forth 字?您可以使用 FCALL 在汇编代码中调用 Forth 字: code x fcall DUP push ebx mov ebx, # 10 fcall DUP next c; 上面这段代码等效于 : X DUP 10 DUP ; 如何在汇编代码中调用 Win32 API ?您可以在汇编代码中使用 FCALL 调用 Win32 API 函数。 code x fcall AllocConsole next c; 等效于 : X call AllocConsole ; |
|||