|
General Development IssuesQuestions about source code strategy Deliverable FilesWhat follows is a description of the files that you must or may ship with a Smalltalk MT executable:
Note: strtdllx.DLL is named strtdll20.dll in Smalltalk MT 2.0 and strtdll25.dll in version 2.5/2.6. Strictly speaking, runtime Dlls are not version-dependant. We changed the functionality exposed by the runtime Dll. In addition, the latest Dlls have been compiled with VC 6, which resulted in an increase in code size. Questions about source code strategy
Back to TopWhat is the purpose of #_asCinteger?The message #_asCinteger is sent implicitly to API arguments, and returns a 32 bit representation of an object. If the object cannot be passed to an API (for example nil), it raises an exception. You can bypass this message with one of the messages #basicAddress,
#_asInteger, or more generally with an inline message that returns a known type
(such as #_longAtOffset:). Note that the address manipulation methods (#atAddress:put: etc.) do not send the message, so you may have to send it yourself if the parameter is not an integer or LONG type. Example: MemoryManager atAddress: ppEnumConnectionPoints put: ienum _asCinteger. Back to TopHow would I do it if I wanted to use runtime binding?It would be similar to what you do in C:
You can take a look at #callProc:with:with: and add more
parameters as you Back to TopIs there a Notifier in Smalltalk MT?Each window implements its own window procedure (although most windows inherit the default window procedure in Window), and exports it to the operating system. A Smalltalk-created window other than a dialog box reserves private data in its window creation structure, and stores the address of the Smalltalk object in that slot (remember: in ST/MT, objects are never moved). A DialogBox functions exactly like a Dialog Box in C/C++ ; each instance has its own dialog procedure that references the Smalltalk object. Back to TopWhat is the purpose of the window property
|
source code in project format (.SP) | |
resources (in a DLL) |
In order to open an application such as Generic, you must first install the project file (generic.sp). The next step is to copy the resources into your path (i.e., copy generic.dll to your image directory). You can then open the application (look at the readme.txt file that comes with the sample to see how to do this).
Some projects require additional components before they can be used. The Project Browser will take care of it automatically (linking with DLLs and installing prerequisite projects).
You must first define a method ApplicationProcess>>winMain:with:with:with: that starts up your main window (or whatever you want to do in the process). Define this method in a file called winmain.sm and place the file in the project directory.
The Project Browser checks for a winmain.sm file in the current project directory before it enables the build EXE menu item.
The generated executable raises an exception at runtime:
---------------------------------------------------------------------------
An instance of "Undefined Object" does not understand the
message "Symbol(16r1000ACA)". The message was sent
by an instance of "TestClient"
---------------------------------------------------------------------------
If you enable all error assertions you'll see the message box of the type "an instance of XXX did not understand Symbol(yyy), the message was sent by an instance of ZZZ".
In the development, evaluate
Symbol value: 16r1000ACA
and it returns #show:.
You can also run the executable in WinDbg or use DBMON on Windows NT to view debugging messages.
a) #basicAddress always returns an integer that is the object's address.
b) once you take an object's address, you must ensure that it is still referenced. The following is wrong:
| findStruct |
findStruct := FINDTEXT new.
findStruct lpstrText: 'Courier',' New'.
The reason is that 'Courier',' New' creates a new string which is stored in a structure. The structure is a byte object and stores the pointer as a 32-bit value, meaning that there are no more references to the string, which can be collected. So, use the code below instead:
| findStruct szText|
findStruct := FINDTEXT new.
szText := 'Courier',' New'.
findStruct lpstrText: szFont.
self doSomethingWith: findStruct.
^'and now szText gets out of scope'
c) to be sure an object is not discarded, you can:
- use #registerObject / #releaseObject
- allocate it on the external heap:
(String heapAlloc: szFont size) replaceFrom: 1 to: szFont size with: szFont; yourself
and free it using heapFree.
ApplicationProcess
is instantiated with the message heapAlloc
.
The method allInstances
only
returns instances allocated on the Smalltalk heap.
To process a window message such as WM_MOUSEMOVE, just implement a method named WM_XXX:with: (for a WM_XXX message). Don't forget to return a value as specified by the documentation of the message.
If the window that receives the message is a Windows control, the method above will not directly work because the window procedure is implemented by the control. First, check whether the control send notification events to its parent. In this case, install an event handler for the notification (using #when:in:perform:). Otherwise, create a Smalltalk subclass of the control that implements the windows message in question, and send it the message #subclassWindow upon creation. The TwinEdit sample on the distribution set demonstrates this.
To exit the development environment programmatically, evaluate:
Processor close
In Smalltalk MT, the standard serialization methods use memory-mapping technology. MappedObjectStream implements an easy-to use interface. An instance of MappedObjectStream maps a set of objects into the address space of the process. The top-level object is called the root object. There is only one root object, but it can be arbitrary, and in particular it can be a collection.
If you open an existing file in RW mode, you can modify any object that resides in the file. When the file is saved, external references are automatically appended to the end of the file. If you wish to add more objects, you can add them to the root collection or to any other object in the file.
See also Object Serialization Example.
The garbage collector (GC) scans all object references. If you close the mapped file while keeping a reference, an otherwise valid reference will suddenly point to nowhere. The GC algorithm assumes that an object reference is always valid. Otherwise, object traversal would be much slower.
See also Object Serialization Example.
It is possible to load and unload ActiveX controls at runtime. One benefit is that an application can delay loading an ActiveX control until it is actually needed, which reduces the application startup time.
The following code fragment loads an ActiveX control (the Microsoft Web Browser Control) dynamically. The application must first create an OleContainerWindow.
| oleContainer if |
oleContainer := self childAt: IDC_CONTROL1.
(if := IClassFactory coCreateInstance: (GUID IIDFromString:
'{8856F961-340A-11D0-A96B-00C04FD705A2}' )
interface: IUnknown) notNil ifTrue: [
oleContainer insertObject: if.
oleContainer invoke: 500 with: 'D:\\index.htm'.
].
To unload the control:
oleContainer unload.
Visitors Since 1/1/2000:
|