请问'Record already locked by this session'如何解决

sparrownet 2003-06-10 10:02:59
我在用dbgrid编辑数据集时,想在一个记录(后一条记录用n1表示)未编辑完时去做别的事,
比如浏览,预览等,那这时我想这个未编辑完的记录自动删除而不加保存,
(我用的query组件:RequestLive=true, CachedUpdates=true)
我采用的是在beforepost前检查记录的完整性,如果不完整,
则调用cancel或delete,操作显示成功(好像速度有点慢),当前活动记录是n1,
当插入新记录时,编辑未完成,这时又调用post,就会出现上面的问题.
请问有那位高手指点迷津,解决这个问题,最好能解释它出现的原理


...全文
114 1 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
sixgj 2003-06-10
  • 打赏
  • 举报
回复
学习中……
Contents Overview 1 Lesson 1: Concepts – Locks and Lock Manager 3 Lesson 2: Concepts – Batch and Transaction 31 Lesson 3: Concepts – Locks and Applications 51 Lesson 4: Information Collection and Analysis 63 Lesson 5: Concepts – Formulating and Implementing Resolution 81 Module 4: Troubleshooting Locking and Blocking Overview At the end of this module, you will be able to:  Discuss how lock manager uses lock mode, lock resources, and lock compatibility to achieve transaction isolation.  Describe the various transaction types and how transactions differ from batches.  Describe how to troubleshoot blocking and locking issues.  Analyze the output of blocking scripts and Microsoft® SQL Server™ Profiler to troubleshoot locking and blocking issues.  Formulate hypothesis to resolve locking and blocking issues. Lesson 1: Concepts – Locks and Lock Manager This lesson outlines some of the common causes that contribute to the perception of a slow server. What You Will Learn After completing this lesson, you will be able to:  Describe locking architecture used by SQL Server.  Identify the various lock modes used by SQL Server.  Discuss lock compatibility and concurrent access.  Identify different types of lock resources.  Discuss dynamic locking and lock escalation.  Differentiate locks, latches, and other SQL Server internal “locking” mechanism such as spinlocks and other synchronization objects. Recommended Reading  Chapter 14 “Locking”, Inside SQL Server 2000 by Kalen Delaney  SOX000821700049 – SQL 7.0 How to interpret lock resource Ids  SOX000925700237 – TITLE: Lock escalation in SQL 7.0  SOX001109700040 – INF: Queries with PREFETCH in the plan hold lock until the end of transaction Locking Concepts Delivery Tip Prior to delivering this material, test the class to see if they fully understand the different isolation levels. If the class is not confident in their understanding, review appendix A04_Locking and its accompanying PowerPoint® file. Transactions in SQL Server provide the ACID properties: Atomicity A transaction either commits or aborts. If a transaction commits, all of its effects remain. If it aborts, all of its effects are undone. It is an “all or nothing” operation. Consistency An application should maintain the consistency of a database. For example, if you defer constraint checking, it is your responsibility to ensure that the database is consistent. Isolation Concurrent transactions are isolated from the updates of other incomplete transactions. These updates do not constitute a consistent state. This property is often called serializability. For example, a second transaction traversing the doubly linked list mentioned above would see the list before or after the insert, but it will see only complete changes. Durability After a transaction commits, its effects will persist even if there are system failures. Consistency and isolation are the most important in describing SQL Server’s locking model. It is up to the application to define what consistency means, and isolation in some form is needed to achieve consistent results. SQL Server uses locking to achieve isolation. Definition of Dependency: A set of transactions can run concurrently if their outputs are disjoint from the union of one another’s input and output sets. For example, if T1 writes some object that is in T2’s input or output set, there is a dependency between T1 and T2. Bad Dependencies These include lost updates, dirty reads, non-repeatable reads, and phantoms. ANSI SQL Isolation Levels An isolation level determines the degree to which data is isolated for use by one process and guarded against interference from other processes. Prior to SQL Server 7.0, REPEATABLE READ and SERIALIZABLE isolation levels were synonymous. There was no way to prevent non-repeatable reads while not preventing phantoms. By default, SQL Server 2000 operates at an isolation level of READ COMMITTED. To make use of either more or less strict isolation levels in applications, locking can be customized for an entire session by setting the isolation level of the session with the SET TRANSACTION ISOLATION LEVEL statement. To determine the transaction isolation level currently set, use the DBCC USEROPTIONS statement, for example: USE pubs GO SET TRANSACTION ISOLATION LEVEL REPEATABLE READ GO DBCC USEROPTIONS GO Multigranular Locking Multigranular Locking In our example, if one transaction (T1) holds an exclusive lock at the table level, and another transaction (T2) holds an exclusive lock at the row level, each of the transactions believe they have exclusive access to the resource. In this scenario, since T1 believes it locks the entire table, it might inadvertently make changes to the same row that T2 thought it has locked exclusively. In a multigranular locking environment, there must be a way to effectively overcome this scenario. Intent lock is the answer to this problem. Intent Lock Intent Lock is the term used to mean placing a marker in a higher-level lock queue. The type of intent lock can also be called the multigranular lock mode. An intent lock indicates that SQL Server wants to acquire a shared (S) lock or exclusive (X) lock on some of the resources lower down in the hierarchy. For example, a shared intent lock placed at the table level means that a transaction intends on placing shared (S) locks on pages or rows within that table. Setting an intent lock at the table level prevents another transaction from subsequently acquiring an exclusive (X) lock on the table containing that page. Intent locks improve performance because SQL Server examines intent locks only at the table level to determine whether a transaction can safely acquire a lock on that table. This removes the requirement to examine every row or page lock on the table to determine whether a transaction can lock the entire table. Lock Mode The code shown in the slide represents how the lock mode is stored internally. You can see these codes by querying the master.dbo.spt_values table: SELECT * FROM master.dbo.spt_values WHERE type = N'L' However, the req_mode column of master.dbo.syslockinfo has lock mode code that is one less than the code values shown here. For example, value of req_mode = 3 represents the Shared lock mode rather than the Schema Modification lock mode. Lock Compatibility These locks can apply at any coarser level of granularity. If a row is locked, SQL Server will apply intent locks at both the page and the table level. If a page is locked, SQL Server will apply an intent lock at the table level. SIX locks imply that we have shared access to a resource and we have also placed X locks at a lower level in the hierarchy. SQL Server never asks for SIX locks directly, they are always the result of a conversion. For example, suppose a transaction scanned a page using an S lock and then subsequently decided to perform a row level update. The row would obtain an X lock, but now the page would require an IX lock. The resultant mode on the page would be SIX. Another type of table lock is a schema stability lock (Sch-S) and is compatible with all table locks except the schema modification lock (Sch-M). The schema modification lock (Sch-M) is incompatible with all table locks. Locking Resources Delivery Tip Note the differences between Key and Key Range locks. Key Range locks will be covered in a couple of slides. SQL Server can lock these resources: Item Description DB A database. File A database file Index An entire index of a table. Table An entire table, including all data and indexes. Extent A contiguous group of data pages or index pages. Page An 8-KB data page or index page. Key Row lock within an index. Key-range A key-range. Used to lock ranges between records in a table to prevent phantom insertions or deletions into a set of records. Ensures serializable transactions. RID A Row Identifier. Used to individually lock a single row within a table. Application A lock resource defined by an application. The lock manager knows nothing about the resource format. It simply compares the 'strings' representing the lock resources to determine whether it has found a match. If a match is found, it knows that resource is already locked. Some of the resources have “sub-resources.” The followings are sub-resources displayed by the sp_lock output: Database Lock Sub-Resources: Full Database Lock (default) [BULK-OP-DB] – Bulk Operation Lock for Database [BULK-OP-LOG] – Bulk Operation Lock for Log Table Lock Sub-Resources: Full Table Lock (default) [UPD-STATS] – Update statistics Lock [COMPILE] – Compile Lock Index Lock sub-Resources: Full Index Lock (default) [INDEX_ID] – Index ID Lock [INDEX_NAME] – Index Name Lock [BULK_ALLOC] – Bulk Allocation Lock [DEFRAG] – Defragmentation Lock For more information, see also… SOX000821700049 SQL 7.0 How to interpret lock resource Ids Lock Resource Block The resource type has the following resource block format: Resource Type (Code) Content DB (2) Data 1: sub-resource; Data 2: 0; Data 3: 0 File (3) Data 1: File ID; Data 2: 0; Data 3: 0 Index (4) Data 1: Object ID; Data 2: sub-resource; Data 3: Index ID Table (5) Data 1: Object ID; Data 2: sub-resource; Data 3: 0. Page (6) Data 1: Page Number; Data 3: 0. Key (7) Data 1: Object ID; Data 2: Index ID; Data 3: Hashed Key Extent (8) Data 1: Extent ID; Data 3: 0. RID (9) Data 1: RID; Data 3: 0. Application (10) Data 1: Application resource name The rsc_bin column of master..syslockinfo contains the resource block in hexadecimal format. For an example of how to decode value from this column using the information above, let us assume we have the following value: 0x000705001F83D775010002014F0BEC4E With byte swapping within each field, this can be decoded as: Byte 0: Flag – 0x00 Byte 1: Resource Type – 0x07 (Key) Byte 2-3: DBID – 0x0005 Byte 4-7: ObjectID – 0x 75D7831F (1977058079) Byte 8-9: IndexID – 0x0001 Byte 10-16: Hash Key value – 0x 02014F0BEC4E For more information about how to decode this value, see also… Inside SQL Server 2000, pages 803 and 806. Key Range Locking Key Range Locking To support SERIALIZABLE transaction semantics, SQL Server needs to lock sets of rows specified by a predicate, such as WHERE salary BETWEEN 30000 AND 50000 SQL Server needs to lock data that does not exist! If no rows satisfy the WHERE condition the first time the range is scanned, no rows should be returned on any subsequent scans. Key range locks are similar to row locks on index keys (whether clustered or not). The locks are placed on individual keys rather than at the node level. The hash value consists of all the key components and the locator. So, for a nonclustered index over a heap, where columns c1 and c2 where indexed, the hash would contain contributions from c1, c2 and the RID. A key range lock applied to a particular key means that all keys between the value locked and the next value would be locked for all data modification. Key range locks can lock a slightly larger range than that implied by the WHERE clause. Suppose the following select was executed in a transaction with isolation level SERIALIZABLE: SELECT * FROM members WHERE first_name between ‘Al’ and ‘Carl’ If 'Al', 'Bob', and 'Dave' are index keys in the table, the first two of these would acquire key range locks. Although this would prevent anyone from inserting either 'Alex' or 'Ben', it would also prevent someone from inserting 'Dan', which is not within the range of the WHERE clause. Prior to SQL Server 7.0, page locking was used to prevent phantoms by locking the entire set of pages on which the phantom would exist. This can be too conservative. Key Range locking lets SQL Server lock only a much more restrictive area of the table. Impact Key-range locking ensures that these scenarios are SERIALIZABLE:  Range scan query  Singleton fetch of nonexistent row  Delete operation  Insert operation However, the following conditions must be satisfied before key-range locking can occur:  The transaction-isolation level must be set to SERIALIZABLE.  The operation performed on the data must use an index range access. Range locking is activated only when query processing (such as the optimizer) chooses an index path to access the data. Key Range Lock Mode Again, the req_mode column of master.dbo.syslockinfo has lock mode code that is one less than the code values shown here. Dynamic Locking When modifying individual rows, SQL Server typically would take row locks to maximize concurrency (for example, OLTP, order-entry application). When scanning larger volumes of data, it would be more appropriate to take page or table locks to minimize the cost of acquiring locks (for example, DSS, data warehouse, reporting). Locking Decision The decision about which unit to lock is made dynamically, taking many factors into account, including other activity on the system. For example, if there are multiple transactions currently accessing a table, SQL Server will tend to favor row locking more so than it otherwise would. It may mean the difference between scanning the table now and paying a bit more in locking cost, or having to wait to acquire a more coarse lock. A preliminary locking decision is made during query optimization, but that decision can be adjusted when the query is actually executed. Lock Escalation When the lock count for the transaction exceeds and is a multiple of ESCALATION_THRESHOLD (1250), the Lock Manager attempts to escalate. For example, when a transaction acquired 1250 locks, lock manager will try to escalate. The number of locks held may continue to increase after the escalation attempt (for example, because new tables are accessed, or the previous lock escalation attempts failed due to incompatible locks held by another spid). If the lock count for this transaction reaches 2500 (1250 * 2), Lock Manager will attempt escalation again. The Lock Manager looks at the lock memory it is using and if it is more than 40 percent of SQL Server’s allocated buffer pool memory, it tries to find a scan (SDES) where no escalation has already been performed. It then repeats the search operation until all scans have been escalated or until the memory used drops under the MEMORY_LOAD_ESCALATION_THRESHOLD (40%) value. If lock escalation is not possible or fails to significantly reduce lock memory footprint, SQL Server can continue to acquire locks until the total lock memory reaches 60 percent of the buffer pool (MAX_LOCK_RESOURCE_MEMORY_PERCENTAGE=60). Lock escalation may be also done when a single scan (SDES) holds more than LOCK_ESCALATION_THRESHOLD (765) locks. There is no lock escalation on temporary tables or system tables. Trace Flag 1211 disables lock escalation. Important Do not relay this to the customer without careful consideration. Lock escalation is a necessary feature, not something to be avoided completely. Trace flags are global and disabling lock escalation could lead to out of memory situations, extremely poor performing queries, or other problems. Lock escalation tracing can be seen using the Profiler or with the general locking trace flag, -T1200. However, Trace Flag 1200 shows all lock activity so it should not be usable on a production system. For more information, see also… SOX000925700237 “TITLE: SQL 7.0 Lock escalation in SQL 7.0” Lock Timeout Application Lock Timeout An application can set lock timeout for a session with the SET option: SET LOCK_TIMEOUT N where N is a number of milliseconds. A value of -1 means that there will be no timeout, which is equivalent to the version 6.5 behavior. A value of 0 means that there will be no waiting; if a process finds a resource locked, it will generate error message 1222 and continue with the next statement. The current value of LOCK_TIMEOUT is stored in the global variable @@lock_timeout. Note After a lock timeout any transaction containing the statement, is rolled back or canceled by SQL Server 2000 (bug#352640 was filed). This behavior is different from that of SQL Server 7.0. With SQL Server 7.0, the application must have an error handler that can trap error 1222 and if an application does not trap the error, it can proceed unaware that an individual statement within a transaction has been canceled, and errors can occur because statements later in the transaction may depend on the statement that was never executed. Bug#352640 is fixed in hotfix build 8.00.266 whereby a lock timeout will only Internal Lock Timeout At time, internal operations within SQL Server will attempt to acquire locks via lock manager. Typically, these lock requests are issued with “no waiting.” For example, the ghost record processing might try to clean up rows on a particular page, and before it can do that, it needs to lock the page. Thus, the ghost record manager will request a page lock with no wait so that if it cannot lock the page, it will just move on to other pages; it can always come back to this page later. If you look at SQL Profiler Lock: Timeout events, internal lock timeout typically have a duration value of zero. Lock Duration Lock Mode and Transaction Isolation Level For REPEATABLE READ transaction isolation level, update locks are held until data is read and processed, unless promoted to exclusive locks. "Data is processed" means that we have decided whether the row in question matched the search criteria; if not then the update lock is released, otherwise, we get an exclusive lock and make the modification. Consider the following query: use northwind go dbcc traceon(3604, 1200, 1211) -- turn on lock tracing -- and disable escalation go set transaction isolation level repeatable read begin tran update dbo.[order details] set discount = convert (real, discount) where discount = 0.0 exec sp_lock Update locks are promoted to exclusive locks when there is a match; otherwise, the update lock is released. The sp_lock output verifies that the SPID does not hold any update locks or shared locks at the end of the query. Lock escalation is turned off so that exclusive table lock is not held at the end. Warning Do not use trace flag 1200 in a production environment because it produces a lot of output and slows down the server. Trace flag 1211 should not be used unless you have done extensive study to make sure it helps with performance. These trace flags are used here for illustration and learning purposes only. Lock Ownership Most of the locking discussion in this lesson relates to locks owned by “transactions.” In addition to transaction, cursor and session can be owners of locks and they both affect how long locks are held. For every row that is fetched, when SCROLL_LOCKS option is used, regardless of the state of a transaction, a cursor lock is held until the next row is fetched or when the cursor is closed. Locks owned by session are outside the scope of a transaction. The duration of these locks are bounded by the connection and the process will continue to hold these locks until the process disconnects. A typical lock owned by session is the database (DB) lock. Locking – Read Committed Scan Under read committed isolation level, when database pages are scanned, shared locks are held when the page is read and processed. The shared locks are released “behind” the scan and allow other transactions to update rows. It is important to note that the shared lock currently acquired will not be released until shared lock for the next page is successfully acquired (this is commonly know as “crabbing”). If the same pages are scanned again, rows may be modified or deleted by other transactions. Locking – Repeatable Read Scan Under repeatable read isolation level, when database pages are scanned, shared locks are held when the page is read and processed. SQL Server continues to hold these shared locks, thus preventing other transactions to update rows. If the same pages are scanned again, previously scanned rows will not change but new rows may be added by other transactions. Locking – Serializable Read Scan Under serializable read isolation level, when database pages are scanned, shared locks are held not only on rows but also on scanned key range. SQL Server continues to hold these shared locks until the end of transaction. Because key range locks are held, not only will this prevent other transactions from modifying the rows, no new rows can be inserted. Prefetch and Isolation Level Prefetch and Locking Behavior The prefetch feature is available for use with SQL Server 7.0 and SQL Server 2000. When searching for data using a nonclustered index, the index is searched for a particular value. When that value is found, the index points to the disk address. The traditional approach would be to immediately issue an I/O for that row, given the disk address. The result is one synchronous I/O per row and, at most, one disk at a time working to evaluate the query. This does not take advantage of striped disk sets. The prefetch feature takes a different approach. It continues looking for more record pointers in the nonclustered index. When it has collected a number of them, it provides the storage engine with prefetch hints. These hints tell the storage engine that the query processor will need these particular records soon. The storage engine can now issue several I/Os simultaneously, taking advantage of striped disk sets to execute multiple operations simultaneously. For example, if the engine is scanning a nonclustered index to determine which rows qualify but will eventually need to visit the data page as well to access columns that are not in the index, it may decide to submit asynchronous page read requests for a group of qualifying rows. The prefetch data pages are then revisited later to avoid waiting for each individual page read to complete in a serial fashion. This data access path requires that a lock be held between the prefetch request and the row lookup to stabilize the row on the page so it is not to be moved by a page split or clustered key update. For our example, the isolation level of the query is escalated to REPEATABLE READ, overriding the transaction isolation level. With SQL Server 7.0 and SQL Server 2000, portions of a transaction can execute at a different transaction isolation level than the entire transaction itself. This is implemented as lock classes. Lock classes are used to control lock lifetime when portions of a transaction need to execute at a stricter isolation level than the underlying transaction. Unfortunately, in SQL Server 7.0 and SQL Server 2000, the lock class is created at the topmost operator of the query and hence released only at the end of the query. Currently there is no support to release the lock (lock class) after the row has been discarded or fetched by the filter or join operator. This is because isolation level can be set at the query level via a lock class, but no lower. Because of this, locks acquired during the query will not be released until the query completes. If prefetch is occurring you may see a single SPID that holds hundreds of Shared KEY or PAG locks even though the connection’s isolation level is READ COMMITTED. Isolation level can be determined from DBCC PSS output. For details about this behavior see “SOX001109700040 INF: Queries with PREFETCH in the plan hold lock until the end of transaction”. Other Locking Mechanism Lock manager does not manage latches and spinlocks. Latches Latches are internal mechanisms used to protect pages while doing operations such as placing a row physically on a page, compressing space on a page, or retrieving rows from a page. Latches can roughly be divided into I/O latches and non-I/O latches. If you see a high number of non-I/O related latches, SQL Server is usually doing a large number of hash or sort operations in tempdb. You can monitor latch activities via DBCC SQLPERF(‘WAITSTATS’) command. Spinlock A spinlock is an internal data structure that is used to protect vital information that is shared within SQL Server. On a multi-processor machine, when SQL Server tries to access a particular resource protected by a spinlock, it must first acquire the spinlock. If it fails, it executes a loop that will check to see if the lock is available and if not, decrements a counter. If the counter reaches zero, it yields the processor to another thread and goes into a “sleep” (wait) state for a pre-determined amount of time. When it wakes, hopefully, the lock is free and available. If not, the loop starts again and it is terminated only when the lock is acquired. The reason for implementing a spinlock is that it is probably less costly to “spin” for a short time rather than yielding the processor. Yielding the processor will force an expensive context switch where:  The old thread’s state must be saved  The new thread’s state must be reloaded  The data stored in the L1 and L2 cache are useless to the processor On a single-processor computer, the loop is not useful because no other thread can be running and thus, no one can release the spinlock for the currently executing thread to acquire. In this situation, the thread yields the processor immediately. Lesson 2: Concepts – Batch and Transaction This lesson outlines some of the common causes that contribute to the perception of a slow server. What You Will Learn After completing this lesson, you will be able to:  Review batch processing and error checking.  Review explicit, implicit and autocommit transactions and transaction nesting level.  Discuss how commit and rollback transaction done in stored procedure and trigger affects transaction nesting level.  Discuss various transaction isolation level and their impact on locking.  Discuss the difference between aborting a statement, a transaction, and a batch.  Describe how @@error, @@transcount, and @@rowcount can be used for error checking and handling. Recommended Reading  Charter 12 “Transactions and Triggers”, Inside SQL Server 2000 by Kalen Delaney Batch Definition SQL Profiler Statements and Batches To help further your understanding of what is a batch and what is a statement, you can use SQL Profiler to study the definition of batch and statement.  Try This: Using SQL Profiler to Analyze Batch 1. Log on to a server with Query Analyzer 2. Startup the SQL Profiler against the same server 3. Start a trace using the “StandardSQLProfiler” template 4. Execute the following using Query Analyzer: SELECT @@VERSION SELECT @@SPID The ‘SQL:BatchCompleted’ event is captured by the trace. It shows both the statements as a single batch. 5. Now execute the following using Query Analyzer {call sp_who()} What shows up? The ‘RPC:Completed’ with the sp_who information. RPC is simply another entry point to the SQL Server to call stored procedures with native data types. This allows one to avoid parsing. The ‘RPC:Completed’ event should be considered the same as a batch for the purposes of this discussion. Stop the current trace and start a new trace using the “SQLProfilerTSQL_SPs” template. Issue the same command as outlines in step 5 above. Looking at the output, not only can you see the batch markers but each statement as executed within the batch. Autocommit, Explicit, and Implicit Transaction Autocommit Transaction Mode (Default) Autocommit mode is the default transaction management mode of SQL Server. Every Transact-SQL statement, whether it is a standalone statement or part of a batch, is committed or rolled back when it completes. If a statement completes successfully, it is committed; if it encounters any error, it is rolled back. A SQL Server connection operates in autocommit mode whenever this default mode has not been overridden by either explicit or implicit transactions. Autocommit mode is also the default mode for ADO, OLE DB, ODBC, and DB-Library. A SQL Server connection operates in autocommit mode until a BEGIN TRANSACTION statement starts an explicit transaction, or implicit transaction mode is set on. When the explicit transaction is committed or rolled back, or when implicit transaction mode is turned off, SQL Server returns to autocommit mode. Explicit Transaction Mode An explicit transaction is a transaction that starts with a BEGIN TRANSACTION statement. An explicit transaction can contain one or more statements and must be terminated by either a COMMIT TRANSACTION or a ROLLBACK TRANSACTION statement. Implicit Transaction Mode SQL Server can automatically or, more precisely, implicitly start a transaction for you if a SET IMPLICIT_TRANSACTIONS ON statement is run or if the implicit transaction option is turned on globally by running sp_configure ‘user options’ 2. (Actually, the bit mask 0x2 must be turned on for the user option so you might have to perform an ‘OR’ operation with the existing user option value.) See SQL Server 2000 Books Online on how to turn on implicit transaction under ODBC and OLE DB (acdata.chm::/ac_8_md_06_2g6r.htm). Transaction Nesting Explicit transactions can be nested. Committing inner transactions is ignored by SQL Server other than to decrements @@TRANCOUNT. The transaction is either committed or rolled back based on the action taken at the end of the outermost transaction. If the outer transaction is committed, the inner nested transactions are also committed. If the outer transaction is rolled back, then all inner transactions are also rolled back, regardless of whether the inner transactions were individually committed. Each call to COMMIT TRANSACTION applies to the last executed BEGIN TRANSACTION. If the BEGIN TRANSACTION statements are nested, then a COMMIT statement applies only to the last nested transaction, which is the innermost transaction. Even if a COMMIT TRANSACTION transaction_name statement within a nested transaction refers to the transaction name of the outer transaction, the commit applies only to the innermost transaction. If a ROLLBACK TRANSACTION statement without a transaction_name parameter is executed at any level of a set of nested transaction, it rolls back all the nested transactions, including the outermost transaction. The @@TRANCOUNT function records the current transaction nesting level. Each BEGIN TRANSACTION statement increments @@TRANCOUNT by one. Each COMMIT TRANSACTION statement decrements @@TRANCOUNT by one. A ROLLBACK TRANSACTION statement that does not have a transaction name rolls back all nested transactions and decrements @@TRANCOUNT to 0. A ROLLBACK TRANSACTION that uses the transaction name of the outermost transaction in a set of nested transactions rolls back all the nested transactions and decrements @@TRANCOUNT to 0. When you are unsure if you are already in a transaction, SELECT @@TRANCOUNT to determine whether it is 1 or more. If @@TRANCOUNT is 0 you are not in a transaction. You can also find the transaction nesting level by checking the sysprocess.open_tran column. See SQL Server 2000 Books Online topic “Nesting Transactions” (acdata.chm::/ac_8_md_06_66nq.htm) for more information. Statement, Transaction, and Batch Abort One batch can have many statements and one transaction can have multiple statements, also. One transaction can span multiple batches and one batch can have multiple transactions. Statement Abort Currently executing statement is aborted. This can be a bit confusing when you start talking about statements in a trigger or stored procedure. Let us look closely at the following trigger: CREATE TRIGGER TRG8134 ON TBL8134 AFTER INSERT AS BEGIN SELECT 1/0 SELECT 'Next command in trigger' END To fire the INSERT trigger, the batch could be as simple as ‘INSERT INTO TBL8134 VALUES(1)’. However, the trigger contains two statements that must be executed as part of the batch to satisfy the clients insert request. When the ‘SELECT 1/0’ causes the divide by zero error, a statement abort is issued for the ‘SELECT 1/0’ statement. Batch and Transaction Abort On SQL Server 2000 (and SQL Server 7.0) whenever a non-informational error is encountered in a trigger, the statement abort is promoted to a batch and transactional abort. Thus, in the example the statement abort for ‘select 1/0’ promotion results in an entire batch abort. No further statements in the trigger or batch will be executed and a rollback is issued. On SQL Server 6.5, the statement aborts immediately and results in a transaction abort. However, the rest of the statements within the trigger are executed. This trigger could return ‘Next command in trigger’ as a result set. Once the trigger completes the batch abort promotion takes effect. Conversely, submitting a similar set of statements in a standalone batch can result in different behavior. SELECT 1/0 SELECT 'Next command in batch' Not considering the set option possibilities, a divide by zero error generally results in a statement abort. Since it is not in a trigger, the promotion to a batch abort is avoided and subsequent SELECT statement can execute. The programmer should add an “if @@ERROR” check immediately after the ‘select 1/0’ to T-SQL execution to control the flow correctly. Aborting and Set Options ARITHABORT If SET ARITHABORT is ON, these error conditions cause the query or batch to terminate. If the errors occur in a transaction, the transaction is rolled back. If SET ARITHABORT is OFF and one of these errors occurs, a warning message is displayed, and NULL is assigned to the result of the arithmetic operation. When an INSERT, DELETE, or UPDATE statement encounters an arithmetic error (overflow, divide-by-zero, or a domain error) during expression evaluation when SET ARITHABORT is OFF, SQL Server inserts or updates a NULL value. If the target column is not nullable, the insert or update action fails and the user receives an error. XACT_ABORT When SET XACT_ABORT is ON, if a Transact-SQL statement raises a run-time error, the entire transaction is terminated and rolled back. When OFF, only the Transact-SQL statement that raised the error is rolled back and the transaction continues processing. Compile errors, such as syntax errors, are not affected by SET XACT_ABORT. For example: CREATE TABLE t1 (a int PRIMARY KEY) CREATE TABLE t2 (a int REFERENCES t1(a)) GO INSERT INTO t1 VALUES (1) INSERT INTO t1 VALUES (3) INSERT INTO t1 VALUES (4) INSERT INTO t1 VALUES (6) GO SET XACT_ABORT OFF GO BEGIN TRAN INSERT INTO t2 VALUES (1) INSERT INTO t2 VALUES (2) /* Foreign key error */ INSERT INTO t2 VALUES (3) COMMIT TRAN SELECT 'Continue running batch 1...' GO SET XACT_ABORT ON GO BEGIN TRAN INSERT INTO t2 VALUES (4) INSERT INTO t2 VALUES (5) /* Foreign key error */ INSERT INTO t2 VALUES (6) COMMIT TRAN SELECT 'Continue running batch 2...' GO /* Select shows only keys 1 and 3 added. Key 2 insert failed and was rolled back, but XACT_ABORT was OFF and rest of transaction succeeded. Key 5 insert error with XACT_ABORT ON caused all of the second transaction to roll back. Also note that 'Continue running batch 2...' is not Returned to indicate that the batch is aborted. */ SELECT * FROM t2 GO DROP TABLE t2 DROP TABLE t1 GO Compile and Run-time Errors Compile Errors Compile errors are encountered during syntax checks, security checks, and other general operations to prepare the batch for execution. These errors can prevent the optimization of the query and thus lead to immediate abort. The statement is not run and the batch is aborted. The transaction state is generally left untouched. For example, assume there are four statements in a particular batch. If the third statement has a syntax error, none of the statements in the batch is executed. Optimization Errors Optimization errors would include rare situations where the statement encounters a problem when attempting to build an optimal execution plan. Example: “too many tables referenced in the query” error is reported because a “work table” was added to the plan. Runtime Errors Runtime errors are those that are encountered during the execution of the query. Consider the following batch: SELECT * FROM pubs.dbo.titles UPDATE pubs.dbo.authors SET au_lname = au_lname SELECT * FROM foo UPDATE pubs.dbo.authors SET au_lname = au_lname If you run the above statements in a batch, the first two statements will be executed, the third statement will fail because table foo does not exist, and the batch will terminate. Deferred Name Resolution is the feature that allows this batch to start executing before resolving the object foo. This feature allows SQL Server to delay object resolution and place a “placeholder” in the query’s execution. The object referenced by the placeholder is resolved until the query is executed. In our example, the execution of the statement “SELECT * FROM foo” will trigger another compile process to resolve the name again. This time, error message 208 is returned. Error: 208, Level 16, State 1, Line 1 Invalid object name 'foo'. Message 208 can be encountered as a runtime or compile error depending on whether the Deferred Name Resolution feature is available. In SQL Server 6.5 this would be considered a compile error and on SQL Server 2000 (and SQL Server7.0) as a runtime error due to Deferred Name Resolution. In the following example, if a trigger referenced authors2, the error is detected as SQL Server attempts to execute the trigger. However, under SQL Server 6.5 the create trigger statement fails because authors2 does not exist at compile time. When errors are encountered in a trigger, generally, the statement, batch, and transaction are aborted. You should be able to observe this by running the following script in pubs database: Create table tblTest(iID int) go create trigger trgInsert on tblTest for INSERT as begin select * from authors select * from authors2 select * from titles end go begin tran select 'Before' insert into tblTest values(1) select 'After' go select @@TRANCOUNT go When run in a batch, the statement and the batch are aborted but the transaction remains active. The follow script illustrates this: begin tran select 'Before' select * from authors2 select 'After' go select @@TRANCOUNT go One other factor in a compile versus runtime error is implicit data type conversions. If you were to run the following statements on SQL Server 6.5 and SQL Server 2000 (and SQL Server 7.0): create table tblData(dtData datetime) go select 1 insert into tblData values(12/13/99) go On SQL Server 6.5, you get an error before execution of the batch begins so no statements are executed and the batch is aborted. Error: 206, Level 16, State 2, Line 2 Operand type clash: int is incompatible with datetime On SQL Server 2000, you get the default value (1900-01-01 00:00:00.000) inserted into the table. SQL Server 2000 implicit data type conversion treats this as integer division. The integer division of 12/13/99 is 0, so the default date and time value is inserted, no error returned. To correct the problem on either version is to wrap the date string with quotes. See Bug #56118 (sqlbug_70) for more details about this situation. Another example of a runtime error is a 605 message. Error: 605 Attempt to fetch logical page %S_PGID in database '%.*ls' belongs to object '%.*ls', not to object '%.*ls'. A 605 error is always a runtime error. However, depending on the transaction isolation level, (e.g. using the NOLOCK lock hint), established by the SPID the handling of the error can vary. Specifically, a 605 error is considered an ACCESS error. Errors associated with buffer and page access are found in the 600 series of errors. When the error is encountered, the isolation level of the SPID is examined to determine proper handling based on information or fatal error level. Transaction Error Checking Not all errors cause transactions to automatically rollback. Although it is difficult to determine exactly which errors will rollback transactions and which errors will not, the main idea here is that programmers must perform error checking and handle errors appropriately. Error Handling Raiserror Details Raiserror seems to be a source of confusion but is really rather simple. Raiserror with severity levels of 20 or higher will terminate the connection. Of course, when the connection is terminated a full rollback of any open transaction will immediately be instantiated by the SQL Server (except distributed transaction with DTC involved). Severity levels lower than 20 will simply result in the error message being returned to the client. They do not affect the transaction scope of the connection. Consider the following batch: use pubs begin tran update authors set au_lname = 'smith' raiserror ('This is bad', 19, 1) with log select @@trancount With severity set at 19, the 'select @@trancount' will be executed after the raiserror statement and will return a value of 1. If severity is changed to 20, then the select statement will not run and the connection is broken. Important Error handling must occur not only in T-SQL batches and stored procedures, but also in application program code. Transactions and Triggers (1 of 2) Basic behavior assumes the implicit transactions setting is set to OFF. This behavior makes it possible to identify business logic errors in a trigger, raise an error, rollback the action, and add an audit table entry. Logically, the insert to the audit table cannot take place before the ROLLBACK action and you would not want to build in the audit table insert into every applications error handler that violated the business rule of the trigger. For more information, see also… SQL Server 2000 Books Online topic “Rollbacks in stored procedure and triggers“ (acdata.chm::/ac_8_md_06_4qcz.htm) IMPLICIT_TRANSACTIONS ON Behavior The behavior of firing other triggers on the same table can be tricky. Say you added a trigger that checks the CODE field. Read only versions of the rows contain the code ‘RO’ and read/write versions use ‘RW.’ Whenever someone tries to delete a row with a code ‘RO’ the trigger issues the rollback and logs an audit table entry. However, you also have a second trigger that is responsible for cascading delete operations. One client could issue the delete without implicit transactions on and only the current trigger would execute and then terminate the batch. However, a second client with implicit transactions on could issue the same delete and the secondary trigger would fire. You end up with a situation in which the cascading delete operations can take place (are committed) but the initial row remains in the table because of the rollback operation. None of the delete operations should be allowed but because the transaction scope was restarted because of the implicit transactions setting, they did. Transactions and Triggers (2 of 2) It is extremely difficult to determine the execution state of a trigger when using explicit rollback statements in combination with implicit transactions. The RETURN statement is not allowed to return a value. The only way I have found to set the @@ERROR is using a ‘raiserror’ as the last execution statement in the last trigger to execute. If you modify the example, this following RAISERROR statement will set @@ERROR to 50000: CREATE TRIGGER trgTest on tblTest for INSERT AS BEGIN ROLLBACK INSERT INTO tblAudit VALUES (1) RAISERROR('This is bad', 14,1) END However, this value does not carry over to a secondary trigger for the same table. If you raise an error at the end of the first trigger and then look at @@ERROR in the secondary trigger the @@ERROR remains 0. Carrying Forward an Active/Open Transaction It is possible to exit from a trigger and carry forward an open transaction by issuing a BEGIN TRAN or by setting implicit transaction on and doing INSERT, UPDATE, or DELETE. Warning It is never recommended that a trigger call BEGIN TRANSACTION. By doing this you increment the transaction count. Invalid code logic, not calling commit transaction, can lead to a situation where the transaction count remains elevated upon exit of the trigger. Transaction Count The behavior is better explained by understanding how the server works. It does not matter whether you are in a transaction, when a modification takes place the transaction count is incremented. So, in the simplest form, during the processing of an insert the transaction count is 1. On completion of the insert, the server will commit (and thus decrement the transaction count). If the commit identifies the transaction count has returned to 0, the actual commit processing is completed. Issuing a commit when the transaction count is greater than 1 simply decrements the nested transaction counter. Thus, when we enter a trigger, the transaction count is 1. At the completion of the trigger, the transaction count will be 0 due to the commit issued at the end of the modification statement (insert). In our example, if the connection was already in a transaction and called the second INSERT, since implicit transaction is ON, the transaction count in the trigger will be 2 as long as the ROLLBACK is not executed. At the end of the insert, the commit is again issued to decrement the transaction reference count to 1. However, the value does not return to 0 so the transaction remains open/active. Subsequent triggers are only fired if the transaction count at the end of the trigger remains greater than or equal to 1. The key to continuation of secondary triggers and the batch is the transaction count at the end of a trigger execution. If the trigger that performs a rollback has done an explicit begin transaction or uses implicit transactions, subsequent triggers and the batch will continue. If the transaction count is not 1 or greater, subsequent triggers and the batch will not execute. Warning Forcing the transaction count after issuing a rollback is dangerous because you can easily loose track of your transaction nesting level. When performing an explicit rollback in a trigger, you should immediately issue a return statement to maintain consistent behavior between a connection with and without implicit transaction settings. This will force the trigger(s) and batch to terminate immediately. One of the methods of dealing with this issue is to run ‘SET IMPLICIT_TRANSACTIONS OFF’ as the first statement of any trigger. Other methods may entails checking @@TRANCOUNT at the end of the trigger and continue to COMMIT the transaction as long as @@TRANCOUNT is greater than 1. Examples The following examples are based on this table: create table tbl50000Insert (iID int NOT NULL) go Note If more than one trigger is used, to guarantee the trigger firing sequence, the sp_settriggerorder command should be used. This command is omitted in these examples to simplify the complexity of the statements. First Example In the first example, the second trigger was never fired and the batch, starting with the insert statement, was aborted. Thus, the print statement was never issued. print('Trigger issues rollback - cancels batch') go create trigger trg50000Insert on tbl50000Insert for INSERT as begin select 'Inserted', * from inserted rollback tran select 'End of trigger', @@TRANCOUNT as 'TRANCOUNT' end go create trigger trg50000Insert2 on tbl50000Insert for INSERT as begin select 'In Trigger2' select 'Trigger 2 Inserted', * from inserted end go insert into tbl50000Insert values(1) print('---------------------- In same batch') select * from tbl50000Insert go -- Cleanup drop trigger trg50000Insert drop trigger trg50000Insert2 go delete from tbl50000Insert Second Example The next example shows that since a new transaction is started, the second trigger will be fired and the print statement in the batch will be executed. Note that the insert is rolled back. print('Trigger issues rollback - increases tran count to continue batch') go create trigger trg50000Insert on tbl50000Insert for INSERT as begin select 'Inserted', * from inserted rollback tran begin tran end go create trigger trg50000Insert2 on tbl50000Insert for INSERT as begin select 'In Trigger2' select 'Trigger 2 Inserted', * from inserted end go insert into tbl50000Insert values(2) print('---------------------- In same batch') select * from tbl50000Insert go -- Cleanup drop trigger trg50000Insert drop trigger trg50000Insert2 go delete from tbl50000Insert Third Example In the third example, the raiserror statement is used to set the @@ERROR value and the BEGIN TRAN statement is used in the trigger to allow the batch to continue to run. print('Trigger issues rollback - uses raiserror to set @@ERROR') go create trigger trg50000Insert on tbl50000Insert for INSERT as begin select 'Inserted', * from inserted rollback tran begin tran -- Increase @@trancount to allow -- batch to continue select @@trancount as ‘Trancount’ raiserror('This is from the trigger', 14,1) end go insert into tbl50000Insert values(3) select @@ERROR as 'ERROR', @@TRANCOUNT as 'Trancount' go -- Cleanup drop trigger trg50000Insert go delete from tbl50000Insert Fourth Example For the fourth example, a second trigger is added to illustrate the fact that @@ERROR value set in the first trigger will not be seen in the second trigger nor will it show up in the batch after the second trigger is fired. print('Trigger issues rollback - uses raiserror to set @@ERROR, not seen in second trigger and cleared in batch') go create trigger trg50000Insert on tbl50000Insert for INSERT as begin select 'Inserted', * from inserted rollback begin tran -- Increase @@trancount to -- allow batch to continue select @@TRANCOUNT as 'Trancount' raiserror('This is from the trigger', 14,1) end go create trigger trg50000Insert2 on tbl50000Insert for INSERT as begin select @@ERROR as 'ERROR', @@TRANCOUNT as 'Trancount' end go insert into tbl50000Insert values(4) select @@ERROR as 'ERROR', @@TRANCOUNT as 'Trancount' go -- Cleanup drop trigger trg50000Insert drop trigger trg50000Insert2 go delete from tbl50000Insert Lesson 3: Concepts – Locks and Applications This lesson outlines some of the common causes that contribute to the perception of a slow server. What You Will Learn After completing this lesson, you will be able to:  Explain how lock hints are used and their impact.  Discuss the effect on locking when an application uses Microsoft Transaction Server.  Identify the different kinds of deadlocks including distributed deadlock. Recommended Reading  Charter 14 “Locking”, Inside SQL Server 2000 by Kalen Delaney  Charter 16 “Query Tuning”, Inside SQL Server 2000 by Kalen Delaney Q239753 – Deadlock Situation Not Detected by SQL Server Q288752 – Blocked SPID Not Participating in Deadlock May Incorrectly be Chosen as victim Locking Hints UPDLOCK If update locks are used instead of shared locks while reading a table, the locks are held until the end of the statement or transaction. UPDLOCK has the advantage of allowing you to read data (without blocking other readers) and update it later with the assurance that the data has not changed since you last read it. READPAST READPAST is an optimizer hint for use with SELECT statements. When this hint is used, SQL Server will read past locked rows. For example, assume table T1 contains a single integer column with the values of 1, 2, 3, 4, and 5. If transaction A changes the value of 3 to 8 but has not yet committed, a SELECT * FROM T1 (READPAST) yields values 1, 2, 4, 5. Tip READPAST only applies to transactions operating at READ COMMITTED isolation and only reads past row-level locks. This lock hint can be used to implement a work queue on a SQL Server table. For example, assume there are many external work requests being thrown into a table and they should be serviced in approximate insertion order but they do not have to be completely FIFO. If you have 4 worker threads consuming work items from the queue they could each pick up a record using read past locking and then delete the entry from the queue and commit when they're done. If they fail, they could rollback, leaving the entry on the queue for the next worker thread to pick up. Caution The READPAST hint is not compatible with HOLDLOCK.  Try This: Using Locking Hints 1. Open a Query Window and connect to the pubs database. 2. Execute the following statements (--Conn 1 is optional to help you keep track of each connection): BEGIN TRANSACTION -- Conn 1 UPDATE titles SET price = price * 0.9 WHERE title_id = 'BU1032' 3. Open a second connection and execute the following statements: SELECT @@lock_timeout -- Conn 2 GO SELECT * FROM titles SELECT * FROM authors 4. Open a third connection and execute the following statements: SET LOCK_TIMEOUT 0 -- Conn 3 SELECT * FROM titles SELECT * FROM authors 5. Open a fourth connection and execute the following statement: SELECT * FROM titles (READPAST) -- Conn 4 WHERE title_ID < 'C' SELECT * FROM authors How many records were returned? 3 6. Open a fifth connection and execute the following statement: SELECT * FROM titles (NOLOCK) -- Conn 5 WHERE title_ID 0 the lock manager also checks for deadlocks every time a SPID gets blocked. So a single deadlock will trigger 20 seconds of more immediate deadlock detection, but if no additional deadlocks occur in that 20 seconds, the lock manager no longer checks for deadlocks at each block and detection again only happens every 5 seconds. Although normally not needed, you may use trace flag -T1205 to trace the deadlock detection process. Note Please note the distinction between application lock and other locks’ deadlock detection. For application lock, we do not rollback the transaction of the deadlock victim but simply return a -3 to sp_getapplock, which the application needs to handle itself. Deadlock Resolution How is a deadlock resolved? SQL Server picks one of the connections as a deadlock victim. The victim is chosen based on either which is the least expensive transaction (calculated using the number and size of the log records) to roll back or in which process “SET DEADLOCK_PRIORITY LOW” is specified. The victim’s transaction is rolled back, held locks are released, and SQL Server sends error 1205 to the victim’s client application to notify it that it was chosen as a victim. The other process can then obtain access to the resource it was waiting on and continue. Error 1205: Your transaction (process ID #%d) was deadlocked with another process and has been chosen as the deadlock victim. Rerun your transaction. Symptoms of deadlocking Error 1205 usually is not written to the SQL Server errorlog. Unfortunately, you cannot use sp_altermessage to cause 1205 to be written to the errorlog. If the client application does not capture and display error 1205, some of the symptoms of deadlock occurring are:  Clients complain of mysteriously canceled queries when using certain features of an application.  May be accompanied by excessive blocking. Lock contention increases the chances that a deadlock will occur. Triggers and Deadlock Triggers promote the deadlock priority of the SPID for the life of the trigger execution when the DEADLOCK PRIORITY is not set to low. When a statement in a trigger causes a deadlock to occur, the SPID executing the trigger is given preferential treatment and will not become the victim. Warning Bug 235794 is filed against SQL Server 2000 where a blocked SPID that is not a participant of a deadlock may incorrectly be chosen as a deadlock victim if the SPID is blocked by one of the deadlock participants and the SPID has the least amount of transaction logging. See KB article Q288752: “Blocked Spid Not Participating in Deadlock May Incorrectly be Chosen as victim” for more information. Distributed Deadlock – Scenario 1 Distributed Deadlocks The term distributed deadlock is ambiguous. There are many types of distributed deadlocks. Scenario 1 Client application opens connection A, begins a transaction, acquires some locks, opens connection B, connection B gets blocked by A but the application is designed to not commit A’s transaction until B completes. Note SQL Server has no way of knowing that connection A is somehow dependent on B – they are two distinct connections with two distinct transactions. This situation is discussed in scenario #4 in “Q224453 INF: Understanding and Resolving SQL Server 7.0 Blocking Problems”. Distributed Deadlock – Scenario 2 Scenario 2 Distributed deadlock involving bound connections. Two connections can be bound into a single transaction context with sp_getbindtoken/sp_bindsession or via DTC. Spid 60 enlists in a transaction with spid 61. A third spid 62 is blocked by spid 60, but spid 61 is blocked by spid 62. Because they are doing work in the same transaction, spid 60 cannot commit until spid 61 finishes his work, but spid 61 is blocked by 62 who is blocked by 60. This scenario is described in article “Q239753 - Deadlock Situation Not Detected by SQL Server.” Note SQL Server 6.5 and 7.0 do not detect this deadlock. The SQL Server 2000 deadlock detection algorithm has been enhanced to detect this type of distributed deadlock. The diagram in the slide illustrates this situation. Resources locked by a spid are below that spid (in a box). Arrows indicate blocking and are drawn from the blocked spid to the resource that the spid requires. A circle represents a transaction; spids in the same transaction are shown in the same circle. Distributed Deadlock – Scenario 3 Scenario 3 Distributed deadlock involving linked servers or server-to-server RPC. Spid 60 on Server 1 executes a stored procedure on Server 2 via linked server. This stored procedure does a loopback linked server query against a table on Server 1, and this connection is blocked by a lock held by Spid 60. Note No version of SQL Server is currently designed to detect this distributed deadlock. Lesson 4: Information Collection and Analysis This lesson outlines some of the common causes that contribute to the perception of a slow server. What You Will Learn After completing this lesson, you will be able to:  Identify specific information needed for troubleshooting issues.  Locate and collect information needed for troubleshooting issues.  Analyze output of DBCC Inputbuffer, DBCC PSS, and DBCC Page commands.  Review information collected from master.dbo.sysprocesses table.  Review information collected from master.dbo.syslockinfo table.  Review output of sp_who, sp_who2, sp_lock.  Analyze Profiler log for query usage pattern.  Review output of trace flags to help troubleshoot deadlocks. Recommended Reading Q244455 - INF: Definition of Sysprocesses Waittype and Lastwaittype Fields Q244456 - INF: Description of DBCC PSS Command for SQL Server 7.0 Q271509 - INF: How to Monitor SQL Server 2000 Blocking Q251004 - How to Monitor SQL Server 7.0 Blocking Q224453 - Understanding and Resolving SQL Server 7.0 Blocking Problem Q282749 – BUG: Deadlock information reported with SQL Server 2000 Profiler Locking and Blocking  Try This: Examine Blocked Processes 1. Open a Query Window and connect to the pubs database. Execute the following statements: BEGIN TRAN -- connection 1 UPDATE titles SET price = price + 1 2. Open another connection and execute the following statement: SELECT * FROM titles-- connection 2 3. Open a third connection and execute sp_who; note the process id (spid) of the blocked process. (Connection 3) 4. In the same connection, execute the following: SELECT spid, cmd, waittype FROM master..sysprocesses WHERE waittype 0 -- connection 3 5. Do not close any of the connections! What was the wait type of the blocked process?  Try This: Look at locks held Assumes all your connections are still open from the previous exercise. • Execute sp_lock -- Connection 3 What locks is the process from the previous example holding? Make sure you run ROLLBACK TRAN in Connection 1 to clean up your transaction. Collecting Information See Module 2 for more about how to gather this information using various tools. Recognizing Blocking Problems How to Recognize Blocking Problems  Users complain about poor performance at a certain time of day, or after a certain number of users connect.  SELECT * FROM sysprocesses or sp_who2 shows non-zero values in the blocked or BlkBy column.  More severe blocking incidents will have long blocking chains or large sysprocesses.waittime values for blocked spids.  Possibl
sdk LCS/Telegraphics Wintab* Interface Specification 1.1: 16- and 32-bit API Reference By Rick Poyner Revised February 11, 2012 This specification was developed in response to a perceived need for a standardized programming inter-face to digitizing tablets, three dimensional position sensors, and other pointing devices by a group of lead-ing digitizer manufacturers and applications developers. The availability of drivers that support the features of the specification will simplify the process of developing Windows appli¬cation programs that in-corporate absolute coordinate input, and enhance the acceptance of ad¬vanced pointing de¬vices among users. This specification is intended to be an open standard, and as such the text and information contained herein may be freely used, copied, or distributed without compensation or licensing restrictions. This document is copyright 1991-2012 by LCS/Telegraphics.* Address questions and comments to: LCS/Telegraphics 150 Rogers St. Cambridge, MA 02142 (617)225-7970 (617)225-7969 FAX Compuserve: 76506,1676 Internet: wintab@pointing.com Note: sections marked with the “(1.1)” are new sections added for specification version 1.1. Sec-tions bearing the “(1.1 modified)” notation contain updated information for specification version 1.1. Version 1.1 Update Notation Conventions 1 1. Background Information 1 1.1. Features of Digitizers 1 1.2. The Windows Environment 1 2. Design Goals 2 2.1. User Control 2 2.2. Ease of Programming 2 2.3. Tablet Sharing 3 2.4. Tablet Feature Support 3 3. Design Concepts 3 3.1. Device Conventions 3 3.2. Device Information 4 3.3. Tablet Contexts 4 3.4. Event Packets 4 3.5. Tablet Managers 5 3.6. Extensions 5 3.7. Persistent Binding of Interface Features (1.1) 6 4. Interface Implementations 6 4.1. File and Module Conventions 6 4.2. Feature Support Options 6 5. Function Reference 7 5.1. Basic Functions 7 5.1.1. WTInfo 8 5.1.2. WTOpen 9 5.1.3. WTClose 10 5.1.4. WTPacketsGet 10 5.1.5. WTPacket 11 5.2. Visibility Functions 11 5.2.1. WTEnable 11 5.2.2. WTOverlap 12 5.3. Context Editing Functions 12 5.3.1. WTConfig 12 5.3.2. WTGet 13 5.3.3. WTSet (1.1 modified) 13 5.3.4. WTExtGet 14 5.3.5. WTExtSet 14 5.3.6. WTSave 15 5.3.7. WTRestore 15 5.4. Advanced Packet and Queue Functions 16 5.4.1. WTPacketsPeek 16 5.4.2. WTDataGet 17 5.4.3. WTDataPeek 17 5.4.4. WTQueuePackets (16-bit only) 18 5.4.5. WTQueuePacketsEx 18 5.4.6. WTQueueSizeGet 19 5.4.7. WTQueueSizeSet 19 5.5. Manager Handle Functions 19 5.5.1. WTMgrOpen 19 5.5.2. WTMgrClose 20 5.6. Manager Context Functions 20 5.6.1. WTMgrContextEnum 20 5.6.2. WTMgrContextOwner 21 5.6.3. WTMgrDefContext 22 5.6.4. WTMgrDefContextEx (1.1) 22 5.7. Manager Configuration Functions 23 5.7.1. WTMgrDeviceConfig 23 5.7.2. WTMgrConfigReplace (16-bit only) 24 5.7.3. WTMgrConfigReplaceEx 24 5.8. Manager Packet Hook Functions 25 5.8.1. WTMgrPacketHook (16-bit only) 26 5.8.2. WTMgrPacketHookEx 26 5.8.3. WTMgrPacketUnhook 29 5.8.4. WTMgrPacketHookDefProc (16-bit only) 30 5.8.5. WTMgrPacketHookNext 30 5.9. Manager Preference Data Functions 31 5.9.1. WTMgrExt 31 5.9.2. WTMgrCsrEnable 32 5.9.3. WTMgrCsrButtonMap 32 5.9.4. WTMgrCsrPressureBtnMarks (16-bit only) 33 5.9.5. WTMgrCsrPressureBtnMarksEx 33 5.9.6. WTMgrCsrPressureResponse 34 5.9.7. WTMgrCsrExt 35 6. Message Reference 36 6.1. Event Messages 36 6.1.1. WT_PACKET 36 6.1.2. WT_CSRCHANGE (1.1) 37 6.2. Context Messages 37 6.2.1. WT_CTXOPEN 37 6.2.2. WT_CTXCLOSE 37 6.2.3. WT_CTXUPDATE 38 6.2.4. WT_CTXOVERLAP 38 6.2.5. WT_PROXIMITY 38 6.3. Information Change Messages 39 6.3.1. WT_INFOCHANGE 39 7. Data Reference 39 7.1. Common Data Types (1.1 modified) 39 7.2. Information Data Structures 41 7.2.1. AXIS 41 7.2.2. Information Categories and Indices (1.1 modified) 42 7.3. Context Data Structures 50 7.3.1. LOGCONTEXT (1.1 modified) 50 7.4. Event Data Structures 55 7.4.1. PACKET (1.1 modified) 55 7.4.2. ORIENTATION 57 7.4.3. ROTATION (1.1) 58 Appendix A. Using PKTDEF.H 59 Appendix B. Extension Definitions 60 B.1. Extensions Programming 60 B.2. Out of Bounds Tracking 61 OBT Programming 61 Information Category 61 Turning OBT On and Off 61 B.3. Function Keys 62 FKEYS Programming 62 Information Category 62 B.4. Tilt 62 TILT Programming 63 Information Category 63 B.5. Cursor Mask 63 CSRMASK Programming 64 Information Category 64 B.6. Extended Button Masks 64 XBTNMASK Programming 64 Information Category 65 VERSION 1.1 UPDATE NOTATION CONVENTIONS Sections marked with the “(1.1)” are new sections added for specification version 1.1. Sections bearing the “(1.1 modified)” notation contain updated information for specification version 1.1. The “(1.1)” notation also marks the definitions of new functions, messages, and data structures. The nota-tion “1.1:” marks new text or commentaries explaining new functionality added to existing features. 1 BACKGROUND INFORMATION This document describes a programming interface for using digitizing tablets and other advanced pointing de¬vices with Microsoft Windows Version 3.0 and above. The design presented here is based on the input of numerous professionals from the pointing device manufacturing and Windows soft¬ware development industries. In this document, the words "tablet" and "digitizer" are used interchange¬ably to mean all absolute point¬ing or digitizing devices that can be made to work with this interface. The definition is not lim¬ited to de¬vices that use a physical tablet. In fact, this specification can support de¬vices that combine rela¬tive and absolute pointing as well as purely relative devices. The following sections describe features of tablets and of the Windows environment that helped mo¬tivate the design. 1.1 Features of Digitizers Digitizing tablets present several problems to device interface authors. • Many tablets have a very high report rate. • Many tablets have many configurable features and types of input information. • Tablets often control the system cursor, provide additional digitizing input, and provide template or macro functions. 1.2 The Windows Environment Programming for tablets in the Windows environment presents additional problems. • Multitasking means multiple applications may have to share the tablet. • The tablet must also be able to control the system cursor and/or the pen (in Pen Windows). • The tablet must work with legacy applications, and with applications written to take advan¬tage of tablet services. • The tablet driver must add minimal speed and memory overhead, so as many applications as possible can run as efficiently as possible. • The user should be able to control how applications use the tablet. The user interface must be ef-ficient, consistent, and customizable. 2 DESIGN GOALS While the tablet interface design must address the technical problems stated above, it must also be useful to the programmers who will write tablet programs, and ultimately, to the tablet users. Four design goals will help clarify these needs, and provide some criteria for evaluating the interface speci¬fication. The goals are user control, ease of programming, tablet sharing, and tablet feature support. 2.1 User Control The user should be able to use and control the tablet in as natural and easy a manner as possible. The user's preferences should take precedence over application requests, where possible. Here are questions to ask when thinking about user control as a design goal: • Can the user understand how applications use the tablet? • Is the interface for controlling tablet functions natural and unobtrusive? • Is the user allowed to change things that help to customize the work environment, but pre¬vented from changing things over which applications must have control? 2.2 Ease of Programming Programming is easiest when the amount of knowledge and effort required matches the task at hand. Writing simple programs should require only a few lines of code and a minimal understanding of the en-vironment. On the other hand, more advanced features and functions should be available to those who need them. The interface should accommodate three kinds of programmers: those who wish to write sim-ple tablet programs, programmers who wish to write complex applications that take full ad¬vantage of tab-let capabilities, and programmers who wish to provide tablet device control features. In addition, the inter-face should accommodate programmers in as many different programming lan¬guages, situations, and en-vironments as possible. Questions to ask when thinking about ease of programming include: • How hard is it to learn the interface and write a simple program that uses tablet input? • Can programmers of complex applications control the features they need? • Are more powerful tablet device control features available? • Can the interface be used in different programming environments? • Is the interface logical, consistent, and robust? 2.3 Tablet Sharing In the Windows environment, multiple applications that use the tablet may be running at once. Each ap-plication will require different services. Applications must be able to get the services they need without getting in each others' way. Questions to ask when thinking about tablet sharing include: • Can tablet applications use the tablet features they need, independent of other applications? • Does the interface prevent a rogue application from "hijacking" the tablet, or causing dead¬locks? • Does the sharing architecture promote efficiency? 2.4 Tablet Feature Support The interface gives standard access to as many features as possible, while leaving room for future ex¬ten-sions and vendor-specific customizations. Applications should be able to get the tablet informa¬tion and services they want, just the way they want them. Users should be able to use the tablet to set up an effi-cient, comfortable work environment. Questions to ask when thinking about tablet feature support include: • Does the interface provide the features applications need? Are any commonly available fea¬tures not supported? • Does the interface provide what users need? Is anything missing? • Are future extensions possible and fairly easy? • Are vendor-specific extensions possible? 3 DESIGN CONCEPTS The proposed interface design depends on several fundamental concepts. Devices and cursor types de-scribe physical hardware configurations. The interface publishes read-only information through a single information interface. Applications interact with the interface by setting up tablet contexts and consuming event packets. Applications may assume interface and hardware control functions by be¬coming tablet managers. The interface provides explicit support for future extensions. 3.1 Device Conventions The interface provides access to one or more devices that produce pointing input. Devices sup¬ported by this interface have some common characteristics. The device must define an absolute or relative coordi-nate space in at least two dimensions for which it can return position data. The device must have a point-ing ap¬para¬tus or method (such as a stylus, or a finger touching a touch pad), called the cursor, that de¬fines the current position. The cursor must be able to return at least one bit of additional state (via a but¬ton, touching a digitizing surface, etc.). Devices may have multiple cursor types that have different physical configurations, or that have differ¬ent numbers of buttons, or return auxiliary information, such as pressure information. Cursor types may also describe different optional hardware configurations. The interface defines a standard orientation for reporting device native coordinates. When the user is viewing the device in its normal position, the coordinate origin will be at the lower left of the device. The coordinate system will be right-handed, that is, the positive x axis points from left to right, and the posi¬tive y axis points either upward or away from the user. The z axis, if supported, points either to¬ward the user or upward. For devices that lay flat on a table top, the x-y plane will be horizontal and the z axis will point upward. For devices that are oriented vertically (for example, a touch screen on a conventional dis¬play), the x-y plane will be vertical, and the z axis will point toward the user. 3.2 Device Information Any program can get descriptive information about the tablet via the WTInfo function. The interface specifies certain information that must be available, but allows new implementations to add new types of information. The basic information includes device identifiers, version numbers, and overall ca¬pabilities. The information items are organized by category and index numbers. The combination of a category and index specifies a single information data item, which may be a scalar value, string, structure, or array. Applica¬tions may retrieve single items or whole categories at once. Some categories are multiplexed. A single category code represents the first of a group of identically in-dexed categories, one for each of a set of similar objects. Multiplexed categories in¬clude those for devices and cur¬sor types. One constructs the category number by adding the defined cate¬gory code to a zero-based device or cursor identification number. The information is read-only for normal tablet applications. Some information items may change during the course of a Windows session; tablet applications receive messages notifying them of changes in tablet information. 3.3 Tablet Contexts Tablet contexts play a central role in the interface; they are the objects that applications use to specify their use of the tablet. Con¬texts include not only the physical area of the tablet that the application will use, but also information about the type, con¬tents, and delivery method for tablet events, as well as other information. Tablet contexts are somewhat analo¬gous to display contexts in the GDI interface model; they contain context information about a spe¬cific application's use of the tablet. An application can open more than one context, but most only need one. Applications can customize their contexts, or they can open a context using a default context specification that is always available. The WTInfo function provides access to the default context specification. Opening a context requires a window handle. The window handle becomes the context's owner and will receive any window messages associated with the context. Contexts are remotely similar to screen windows in that they can physically overlap. The tablet inter¬face uses a combination of context overlap order and context attributes to decide which context will process a given event. The topmost context in the overlap order whose input context encompasses the event, and whose event masks select the event, will process the event. (Note that the notion of overlap order is sepa-rate from the notion of the physical z dimension.) Tablet managers (described below) provide a way to modify and overlap contexts. 3.4 Event Packets Tablet contexts generate and report tablet activity via event packets. Applications can control how they receive events, which events they receive, and what information they contain. Applications may receive events either by polling, or via Windows messages. • Polling: Any application that has opened a context can call the WTPacketsGet function to get the next state of the tablet for that context. • Window Messages: Applications that request messages will receive the WT_PACKET mes¬sage (described below), which indicates that something happened in the context and provides a refer-ence to more information. Applications can control which events they receive by using event masks. For example, some appli¬ca¬tions may only need to know when a button is pressed, while others may need to receive an event every time the cursor moves. Tablet context event masks implement this type of control. Applications can control the contents of the event packets they receive. Some tablets can return data that many applications will not need, like button pressure and three dimensional position and orien¬tation in-formation. The context object provides a way of specifying which data items the appli¬cation needs. This allows the driver to improve the efficiency of packet delivery to applications that only need a few items per packet. Packets are stored in context-specific packet queues and retrieved by explicit function calls. The interface provides ways to peek at and get packets, to query the size and contents of the queue, and to re-size the queue. 3.5 Tablet Managers The interface provides functions for tablet management. An application can become a tablet manager by opening a tablet manager handle. This handle allows the manager access to spe¬cial functions. These man-agement functions allow the application to arrange, overlap, and modify tablet contexts. Man¬agers may also perform other functions, such as changing default values used by applica¬tions, chang¬ing ergo¬nomic, preference, and configuration settings, controlling tablet behavior with non-tablet aware applica¬tions, modi¬fy¬ing user dialogs, and recording and playing back tablet packets. Opening a manager handle re¬quires a window handle. The window becomes a manager window and receives window messages about interface and con¬text activity. 3.6 Extensions The interface allows implementations to define additional features called extensions. Extensions can be made available to new applications without the need to modify ex¬isting applications. Extensions are sup-ported through the information categories, through the flexible definition of packets, and through special context and manager functions. Designing an extension involves defining the meaning and behavior of the extension packet and/or prefer-ence data, filling in the information category, defining the extension's interface with the special functions, and possibly defining additional functions to support the extension. Each extension will be assigned a unique tag for identification. Not all implementations will support all extensions. A multiplexed information category contains descriptive data about extensions. Note that applica¬tions must find their extensions by iterating through the categories and matching tags. While tags are fixed across all implementations, category numbers may vary among implementations. 3.7 Persistent Binding of Interface Features (1.1) The interface provides access to many of its features using consecutive numeric indices whose value is not guaranteed from session to session. However, sufficient information is provided to create unique identifi¬ers for devices, cursors, and interface extensions. Devices should be uniquely identified by the contents of their name strings. If multiple identical devices are present, implementation providers should provide unique, persistent id strings to the extent possible. Identical devices that return unique serial numbers are ideal. If supported by the hardware, cursors also may have a physical cursor id that uniquely identifies the cursor in a persistent and stable manner. Interface extensions are uniquely identified by their tag. 4 INTERFACE IMPLEMENTATIONS Implementations of this interface usually support one specific device, a class of similar devices, or a com-mon combination of devices. The following sections discuss guidelines for implementations. 4.1 File and Module Conventions For 16-bit implementations, the interface functions, and any additional vendor- or device-specific func-tions, reside in a dynamic link library with the file name "WINTAB.DLL" and module name "WINTAB"; 32-bit implementations use the file name "WINTAB32.DLL" and module name "WINTAB32." Any other file or module con¬ventions are implementation specific. Implementations may include other library mod-ules or data files as necessary. Installation processes are likewise implementa¬tion-specific. Wintab programs written in the C language require two header files. WINTAB.H contains definitions of all of the functions, constants, and fixed data types. PKTDEF.H contains a parameterized definition of the PACKET data structure, that can be tailored to fit the application. The Wintab Programmer's Kit con¬tains these and other files necessary for Wintab programming, plus several example programs with C-lan¬guage source files. The Wintab Programmer's Kit is available from the author. 4.2 Feature Support Options Some features of the interface are optional and may be left out by some implementations. Support of defined data items other than x, y, and buttons is optional. Many devices only report x, y, and button information. Support of system-cursor contexts is optional. This option relieves implementations of replacing the sys¬tem mouse driver in Windows versions before 3.1. Support of Pen Windows contexts is optional. Not all systems will have the Pen Windows hardware and software necessary. Support of external tablet manager applications is optional, and the number of manager handles is imple-mentation-dependent. However, the manager functions should be present in all implementa¬tions, return¬ing appropriate failure codes if not fully implemented. An implementation may provide context- and hardware-management support internally only, if desired. On the other hand, providing the external man-ager interface may relieve the implementation of a considerable amount of user in¬terface code, and make improvements to the manager interface easier to implement and distribute later. Support of extension data items is optional. Most extensions will be geared to unusual hardware features. 5 FUNCTION REFERENCE All tablet function names have the prefix "WT" and have attributes equivalent to WINAPI. Applica¬tions gain access to the tablet interface functions through a dynamic-link library with standard file and module names, as defined in the previous section. Applications may link to the functions by using the Windows functions LoadLibrary, FreeLibrary, and GetProcAddress, or use an import library. Specific to 32-bit Wintab: The functions WTInfo, WTOpen, WTGet, and WTSet have both ANSI and Unicode versions, using the same ANSI/Unicode porting conventions used in the Win32 API. Five non-portable functions, WTQueuePackets, WTMgrCsrPressureBtnMarks, WTMgrConfigReplace, WTMgrPacketHook, and WTMgrPacketHookDefProc are replaced by new portable functions WTQueuePacketsEx, WTMgrCsrPressureBtnMarksEx, WTMgrConfigReplaceEx, WTMgrPack-etHookEx, WTMgrPacketUnhook, and WTMgrPacketHookNext. WTMgrConfigReplaceEx and WTMgrPacketHookEx have both ANSI and Unicode versions. Table 5.1. Ordinal Function Numbers for Dynamic Linking Ordinal numbers for dynamic linking are defined in the table below. Where two ordinal entries appear, the first entry identifies the 16-bit and 32-bit ANSI versions of the function. The second entry identifies the 32-bit Unicode version. Function Name Ordinal Function Name Ordinal WTInfo 20, 1020 WTMgrOpen 100 WTOpen 21, 1021 WTMgrClose 101 WTClose 22 WTMgrContextEnum 120 WTPacketsGet 23 WTMgrContextOwner 121 WTPacket 24 WTMgrDefContext 122 WTEnable 40 WTMgrDefContextEx (1.1) 206 WTOverlap 41 WTMgrDeviceConfig 140 WTConfig 60 WTMgrConfigReplace 141 WTGet 61, 1061 WTMgrConfigReplaceEx 202, 1202 WTSet 62, 1062 WTMgrPacketHook 160 WTExtGet 63 WTMgrPacketHookEx 203, 1203 WTExtSet 64 WTMgrPacketUnhook 204 WTSave 65 WTMgrPacketHookDefProc 161 WTRestore 66 WTMgrPacketHookNext 205 WTPacketsPeek 80 WTMgrExt 180 WTDataGet 81 WTMgrCsrEnable 181 WTDataPeek 82 WTMgrCsrButtonMap 182 WTQueuePackets 83 WTMgrCsrPressureBtnMarks 183 WTQueuePacketsEx 200 WTMgrCsrPressureBtnMarksEx 201 WTQueueSizeGet 84 WTMgrCsrPressureResponse 184 WTQueueSizeSet 85 WTMgrCsrExt 185 5.1 Basic Functions The functions in the following section will be used by most tablet-aware applications. They include getting interface and device information, opening and closing contexts, and retrieving packets by polling or via Windows messages. 5.1.1 WTInfo Syntax UINT WTInfo(wCategory, nIndex, lpOutput) This function returns global information about the interface in an application-sup-plied buffer. Different types of information are specified by different index argu-ments. Applications use this function to receive information about tablet coordi-nates, physical dimensions, capabilities, and cursor types. Parameter Type/Description wCategory UINT Identifies the category from which information is being re-quested. nIndex UINT Identifies which information is being requested from within the category. lpOutput LPVOID Points to a buffer to hold the requested information. Return Value The return value specifies the size of the returned information in bytes. If the infor-mation is not supported, the function returns zero. If a tablet is not physi¬cally pres-ent, this function always returns zero. Comments Several important categories of information are available through this function. First, the function provides identification information, including specification and software version numbers, and tablet vendor and model information. Sec¬ond, the function provides general capability information, including dimensions, resolutions, optional features, and cursor types. Third, the function provides categories that give defaults for all tablet context attributes. Finally, the func¬tion may provide any other implementation- or vendor-specific information cat¬egories necessary. The information returned by this function is subject to change during a Win¬dows session. Applications cannot change the information returned here, but tablet man-ager applications or hardware changes or errors can. Applications can respond to information changes by fielding the WT_INFOCHANGE message. The parameters of the message indicate which information has changed. If the wCategory argument is zero, the function copies no data to the output buffer, but returns the size in bytes of the buffer necessary to hold the largest complete category. If the nIndex argument is zero, the function returns all of the information entries in the category in a single data structure. If the lpOutput argument is NULL, the function just returns the required buffer size. See Also Category and index definitions in tables 7.3 through 7.9, and the WT_INFOCHANGE message in section 6.3.1. 5.1.2 WTOpen Syntax HCTX WTOpen(hWnd, lpLogCtx, fEnable) This function establishes an active context on the tablet. On successful comple¬tion of this function, the application may begin receiving tablet events via mes¬sages (if they were requested), and may use the handle returned to poll the con¬text, or to per-form other context-related functions. Parameter Type/Description hWnd HWND Identifies the window that owns the tablet context, and receives messages from the context. lpLogCtx LPLOGCONTEXT Points to an application-provided LOGCONTEXT data structure describing the context to be opened. fEnable BOOL Specifies whether the new context will immediately begin processing input data. Return Value The return value identifies the new context. It is NULL if the context is not opened. Comments Opening a new context allows the application to receive tablet input or creates a context that controls the system cursor or Pen Windows pen. The owning window (and all manager windows) will immediately receive a WT_CTXOPEN message when the context has been opened. If the fEnable argument is zero, the context will be created, but will not process input. The context can be enabled using the WTEnable function. If tablet event messages were requested in the context specification, the owning window will receive them. The application can control the message numbers used the lcMsgBase field of the LOGCONTEXT structure. The window that owns the new context will receive context and information change messages even if event messages were not requested. It is not necessary to handle these in many cases, but some applications may wish to do so. The newly opened tablet context will be placed on the top of the context overlap or-der. Invalid or out-of-range attribute values in the logical context structure will ei¬ther be validated, or cause the open to fail, depending on the attributes involved. Upon a successful return from the function, the context specification pointed to by lpLogCtx will contain the validated values. See Also The WTEnable function in section 5.2.1, the LOGCONTEXT data structure in section 7.3.1, and the context and infor¬mation change messages in sections 6.2 and 6.3. 5.1.3 WTClose Syntax BOOL WTClose(hCtx) This function closes and destroys the tablet context object. Parameter Type/Description hCtx HCTX Identifies the context to be closed. Return Value The function returns a non-zero value if the context was valid and was destroyed. Otherwise, it returns zero. Comments After a call to this function, the passed handle is no longer valid. The owning win¬dow (and all manager windows) will receive a WT_CTXCLOSE message when the context has been closed. See Also The WTOpen function in section 5.1.2. 5.1.4 WTPacketsGet Syntax int WTPacketsGet(hCtx, cMaxPkts, lpPkts) This function copies the next cMaxPkts events from the packet queue of context hCtx to the passed lpPkts buffer and removes them from the queue. Parameter Type/Description hCtx HCTX Identifies the context whose packets are being returned. cMaxPkts int Specifies the maximum number of packets to return. lpPkts LPVOID Points to a buffer to receive the event packets. Return Value The return value is the number of packets copied in the buffer. Comments The exact structure of the returned packet is determined by the packet infor¬mation that was requested when the context was opened. The buffer pointed to by lpPkts must be at least cMaxPkts * sizeof(PACKET) bytes long to prevent overflow. Applications may flush packets from the queue by calling this function with a NULL lpPkt argument. See Also The WTPacketsPeek function in section 5.4.1, and the descriptions of the LOGCONTEXT (section 7.3.1) and PACKET (section 7.4.1) data structures. 5.1.5 WTPacket Syntax BOOL WTPacket(hCtx, wSerial, lpPkt) This function fills in the passed lpPkt buffer with the context event packet having the specified serial number. The returned packet and any older packets are removed from the context's internal queue. Parameter Type/Description hCtx HCTX Identifies the context whose packets are being returned. wSerial UINT Serial number of the tablet event to return. lpPkt LPVOID Points to a buffer to receive the event packet. Return Value The return value is non-zero if the specified packet was found and returned. It is zero if the specified packet was not found in the queue. Comments The exact structure of the returned packet is determined by the packet infor¬mation that was requested when the context was opened. The buffer pointed to by lpPkts must be at least sizeof(PACKET) bytes long to pre-vent overflow. Applications may flush packets from the queue by calling this function with a NULL lpPkts argument. See Also The descriptions of the LOGCONTEXT (section 7.3.1) and PACKET (section 7.4.1) data structures. 5.2 Visibility Functions The functions in this section allow applications to control contexts' visibility, whether or not they are pro-cessing input, and their overlap order. 5.2.1 WTEnable Syntax BOOL WTEnable(hCtx, fEnable) This function enables or disables a tablet context, temporarily turning on or off the processing of packets. Parameter Type/Description hCtx HCTX Identifies the context to be enabled or disabled. fEnable BOOL Specifies enabling if non-zero, disabling if zero. Return Value The function returns a non-zero value if the enable or disable request was satis¬fied, zero otherwise. Comments Calls to this function to enable an already enabled context, or to disable an al¬ready disabled context will return a non-zero value, but otherwise do nothing. The context’s packet queue is flushed on disable. Applications can determine whether a context is currently enabled by using the WTGet function and examining the lcStatus field of the LOGCONTEXT struc¬ture. See Also The WTGet function in section 5.3.2, and the LOGCONTEXT structure in sec¬tion 7.3.1. 5.2.2 WTOverlap Syntax BOOL WTOverlap(hCtx, fToTop) This function sends a tablet context to the top or bottom of the order of over¬lapping tablet contexts. Parameter Type/Description hCtx HCTX Identifies the context to move within the overlap order. fToTop BOOL Specifies sending the context to the top of the overlap or-der if non-zero, or to the bottom if zero. Return Value The function returns non-zero if successful, zero otherwise. Comments Tablet contexts' input areas are allowed to overlap. The tablet interface main¬tains an overlap order that helps determine which context will process a given event. The topmost context in the overlap order whose input context encom¬passes the event, and whose event masks select the event will process the event. This function is useful for getting access to input events when the application's con-text is overlapped by other contexts. The function will fail only if the context argument is invalid. 5.3 Context Editing Functions This group of functions allows applications to edit, save, and restore contexts. 5.3.1 WTConfig Syntax BOOL WTConfig(hCtx, hWnd) This function prompts the user for changes to the passed context via a dialog box. Parameter Type/Description hCtx HCTX Identifies the context that the user will modify via the dialog box. hWnd HWND Identifies the window that will be the parent window of the dialog box. Return Value The function returns a non-zero value if the tablet context was changed, zero oth-erwise. Comments Tablet applications can use this function to let the user choose context attributes that the application doesn't need to control. Applications can control the editing of con¬text attributes via the lcLocks logical context structure member. Applications should consider providing access to this function through a menu item or command. See Also The LOGCONTEXT structure in section 7.3.1 and the context lock values in table 7.13. 5.3.2 WTGet Syntax BOOL WTGet(hCtx, lpLogCtx) This function fills the passed structure with the current context attributes for the passed handle. Parameter Type/Description hCtx HCTX Identifies the context whose attributes are to be copied. lpLogCtx LPLOGCONTEXT Points to a LOGCONTEXT data structure to which the context attributes are to be copied. Return Value The function returns a non-zero value if the data is retrieved successfully. Oth¬er¬wise, it returns zero. See Also The LOGCONTEXT structure in section 7.3.1. 5.3.3 WTSet (1.1 modified) Syntax BOOL WTSet(hCtx, lpLogCtx) This function allows some of the context's attributes to be changed on the fly. Parameter Type/Description hCtx HCTX Identifies the context whose attributes are being changed. lpLogCtx LPLOGCONTEXT Points to a LOGCONTEXT data structure containing the new context attributes. Return Value The function returns a non-zero value if the context was changed to match the passed context specification; it returns zero if any of the requested changes could not be made. Comments If this function is called by the task or process that owns the context, any context attribute may be changed. Otherwise, the function can change attributes that do not affect the format or meaning of the context's event packets and that were not speci-fied as locked when the context was opened. Context lock values can only be changed by the context’s owner. 1.1: If the hCtx argument is a default context handle returned from WTMgrDef-Context or WTMgrDefContextEx, and the lpLogCtx argument is WTP_LPDEFAULT, the default context will be reset to its initial factory default values. See Also The LOGCONTEXT structure in section 7.3.1 and the context lock values in table 7.13. 5.3.4 WTExtGet Syntax BOOL WTExtGet(hCtx, wExt, lpData) This function retrieves any context-specific data for an extension. Parameter Type/Description hCtx HCTX Identifies the context whose extension attributes are being retrieved. wExt UINT Identifies the extension tag for which context-specific data is being retrieved. lpData LPVOID Points to a buffer to hold the retrieved data. Return Value The function returns a non-zero value if the data is retrieved successfully. Oth¬er¬wise, it returns zero. See Also The extension definitions in Appendix B. 5.3.5 WTExtSet Syntax BOOL WTExtSet(hCtx, wExt, lpData) This function sets any context-specific data for an extension. Parameter Type/Description hCtx HCTX Identifies the context whose extension attributes are being modified. wExt UINT Identifies the extension tag for which context-specific data is being modified. lpData LPVOID Points to the new data. Return Value The function returns a non-zero value if the data is modified successfully. Oth¬er¬wise, it returns zero. Comments Extensions may forbid their context-specific data to be changed during the life¬time of a context. For such extensions, calls to this function would always fail. Extensions may also limit context data editing to the task of the owning window, as with the context locks. See Also The extension definitions in Appendix B, the LOGCONTEXT data structure in section 7.3.1 and the context locking values in table 7.13. 5.3.6 WTSave Syntax BOOL WTSave(hCtx, lpSaveInfo) This function fills the passed buffer with binary save information that can be used to restore the equivalent context in a subsequent Windows session. Parameter Type/Description hCtx HCTX Identifies the context that is being saved. lpSaveInfo LPVOID Points to a buffer to contain the save information. Return Value The function returns non-zero if the save information is successfully retrieved. Oth-erwise, it returns zero. Comments The size of the save information buffer can be determined by calling the WTInfo function with category WTI_INTERFACE, index IFC_CTXSAVESIZE. The save information is returned in a private binary data format. Applications should store the information unmodified and recreate the context by passing the save information to the WTRestore function. Using WTSave and WTRestore allows applications to easily save and restore ex-tension data bound to contexts. See Also The WTRestore function in section 5.3.7. 5.3.7 WTRestore Syntax HCTX WTRestore(hWnd, lpSaveInfo, fEnable) This function creates a tablet context from save information returned from the WTSave function. Parameter Type/Description hWnd HWND Identifies the window that owns the tablet context, and receives messages from the context. lpSaveInfo LPVOID Points to a buffer containing save information. fEnable BOOL Specifies whether the new context will immediately begin processing input data. Return Value The function returns a valid context handle if successful. If a context equivalent to the save information could not be created, the function returns NULL. Comments The save information is in a private binary data format. Applications should only pass save information retrieved by the WTSave function. This function is much like WTOpen, except that it uses save in¬formation for input instead of a logical context. In particular, it will generate a WT_CTXOPEN mes¬sage for the new context. See Also The WTOpen function in section 5.1.2, the WTSave function in section 5.3.6, and the WT_CTXOPEN message in section 6.2.1. 5.4 Advanced Packet and Queue Functions These functions provide advanced packet retrieval and queue manipulation. The packet retrieval functions require the application to provide a packet output buffer. To prevent overflow, the buffer must be large enough to hold the requested number of packets from the specified context. It is up to the caller to deter¬mine the packet size (by interrogating the context, if necessary), and to allocate a large enough buffer. Ap¬plications may flush packets from the queue by passing a NULL buffer pointer. 5.4.1 WTPacketsPeek Syntax int WTPacketsPeek(hCtx, cMaxPkts, lpPkts) This function copies the next cMaxPkts events from the packet queue of context hCtx to the passed lpPkts buffer without removing them from the queue. Parameter Type/Description hCtx HCTX Identifies the context whose packets are being read. cMaxPkts int Specifies the maximum number of packets to return. lpPkts LPVOID Points to a buffer to receive the event packets. Return Value The return value is the number of packets copied in the buffer. Comments The buffer pointed to by lpPkts must be at least cMaxPkts * sizeof(PACKET) bytes long to prevent overflow. See Also the WTPacketsGet function in section 5.1.4. 5.4.2 WTDataGet Syntax int WTDataGet(hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts) This function copies all packets with serial numbers between wBegin and wEnd in-clusive from the context's queue to the passed buffer and removes them from the queue. Parameter Type/Description hCtx HCTX Identifies the context whose packets are being returned. wBegin UINT Serial number of the oldest tablet event to return. wEnd UINT Serial number of the newest tablet event to return. cMaxPkts int Specifies the maximum number of packets to return. lpPkts LPVOID Points to a buffer to receive the event packets. lpNPkts LPINT Points to an integer to receive the number of packets ac-tually copied. Return Value The return value is the total number of packets found in the queue between wBegin and wEnd. Comments The buffer pointed to by lpPkts must be at least cMaxPkts * sizeof(PACKET) bytes long to prevent overflow. See Also The WTDataPeek function in section 5.4.3, and the WTQueuePacketsEx function in section 5.4.5. 5.4.3 WTDataPeek Syntax int WTDataPeek(hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts) This function copies all packets with serial numbers between wBegin and wEnd in-clusive, from the context's queue to the passed buffer without removing them from the queue. Parameter Type/Description hCtx HCTX Identifies the context whose packets are being read. wBegin UINT Serial number of the oldest tablet event to return. wEnd UINT Serial number of the newest tablet event to return. cMaxPkts int Specifies the maximum number of packets to return. lpPkts LPVOID Points to a buffer to receive the event packets. lpNPkts LPINT Points to an integer to receive the number of packets ac-tually copied. Return Value The return value is the total number of packets found in the queue between wBegin and wEnd. Comments The buffer pointed to by lpPkts must be at least cMaxPkts * sizeof(PACKET) bytes long to prevent overflow. See Also The WTDataGet function in section 5.4.2, and the WTQueuePacketsEx function in section 5.4.5. 5.4.4 WTQueuePackets (16-bit only) Syntax DWORD WTQueuePackets(hCtx) This function returns the serial numbers of the oldest and newest packets cur¬rently in the queue. Parameter Type/Description hCtx HCTX Identifies the context whose queue is being queried. Return Value The high word of the return value contains the newest packet's serial number; the low word contains the oldest. Comments This function is non-portable and is superseded by WTQueuePacketsEx. See Also The WTQueuePacketsEx function in section 5.4.5. 5.4.5 WTQueuePacketsEx Syntax BOOL WTQueuePacketsEx(hCtx, lpOld, lpNew) This function returns the serial numbers of the oldest and newest packets cur¬rently in the queue. Parameter Type/Description hCtx HCTX Identifies the context whose queue is being queried. lpOld UINT FAR * Points to an unsigned integer to receive the oldest packet's serial number. lpNew UINT FAR * Points to an unsigned integer to receive the newest packet's serial number. Return Value The function returns non-zero if successful, zero otherwise. 5.4.6 WTQueueSizeGet Syntax int WTQueueSizeGet(hCtx) This function returns the number of packets the context's queue can hold. Parameter Type/Description hCtx HCTX Identifies the context whose queue size is being re¬turned. Return Value The return value is the number of packet the queue can hold. See Also The WTQueueSizeSet function in section 5.4.7. 5.4.7 WTQueueSizeSet Syntax BOOL WTQueueSizeSet(hCtx, nPkts) This function attempts to change the context's queue size to the value specified in nPkts. Parameter Type/Description hCtx HCTX Identifies the context whose queue size is being set. nPkts int Specifies the requested queue size. Return Value The return value is non-zero if the queue size was successfully changed. Other¬wise, it is zero. Comments If the return value is zero, the context has no queue because the function deletes the original queue before attempting to create a new one. The application must continue calling the function with a smaller queue size until the function returns a non-zero value. See Also The WTQueueSizeGet function in section 5.4.6. 5.5 Manager Handle Functions The functions described in this and subsequent sections are for use by tablet manager applications. The functions of this section create and destroy manager handles. These handles allow the interface code to limit the degree of simultaneous access to the powerful manager functions. Also, opening a manager handle lets the application receive messages about tablet interface activity. 5.5.1 WTMgrOpen Syntax HMGR WTMgrOpen(hWnd, wMsgBase) This function opens a tablet manager handle for use by tablet manager and con¬figu-ration applications. This handle is required to call the tablet management func¬tions. Parameter Type/Description hWnd HWND Identifies the window which owns the manager handle. wMsgBase UINT Specifies the message base number to use when notifying the manager window. Return Value The function returns a manager handle if successful, otherwise it returns NULL. Comments While the manager handle is open, the manager window will receive context mes-sages from all tablet contexts. Manager windows also receive information change messages. The number of manager handles available is interface implementation-dependent, and can be determined by calling the WTInfo function with category WTI_INTERFACE and index IFC_NMANAGERS. See Also The WTInfo function in section 5.1.1, the WTMgrClose function in section 5.5.2, the description of message base numbers in section 6 and the context and in¬for¬ma-tion change messages in sections 6.2 and 6.3. 5.5.2 WTMgrClose Syntax BOOL WTMgrClose(hMgr) This function closes a tablet manager handle. After this function returns, the passed manager handle is no longer valid. Parameter Type/Description hMgr HMGR Identifies the manager handle to close. Return Value The function returns non-zero if the handle was valid; otherwise, it returns zero. 5.6 Manager Context Functions These functions provide access to all open contexts and their owners, and allow changing context de¬faults. Only tablet managers are allowed to manipulate tablet contexts belonging to other applica¬tions. 5.6.1 WTMgrContextEnum Syntax BOOL WTMgrContextEnum(hMgr, lpEnumFunc, lParam) This function enumerates all tablet context handles by passing the handle of each context, in turn, to the callback function pointed to by the lpEnumFunc pa¬rameter. The enumeration terminates when the callback function returns zero. Parameter Type/Description hMgr HMGR Is the valid manager handle that identifies the caller as a manager application. lpEnumFunc WTENUMPROC Is the procedure-instance address of the call-back function. See the following "Comments" section for details. lParam LPARAM Specifies the value to be passed to the callback func-tion for the application's use. Return Value The return value specifies the outcome of the function. It is non-zero if all con¬texts have been enumerated. Otherwise, it is zero. Comments The address passed as the lpEnumFunc parameter must be created by using the MakeProcInstance function. The callback function must have attributes equivalent to WINAPI. The callback function must have the following form: Callback BOOL WINAPI EnumFunc(hCtx, lParam) HCTX hCtx; LPARAM lParam; EnumFunc is a place holder for the application-supplied function name. The actual name must be exported by including it in an EXPORTS statement in the applica-tion's module-definition file. Parameter Description hCtx Identifies the context. lParam Specifies the 32-bit argument of the WTMgrContextEnum func-tion. Return Value The function must return a non-zero value to continue enumeration, or zero to stop it. 5.6.2 WTMgrContextOwner Syntax HWND WTMgrContextOwner(hMgr, hCtx) This function returns the handle of the window that owns a tablet context. Parameter Type/Description hMgr HMGR Is the valid manager handle that identifies the caller as a manager application. hCtx HCTX Identifies the context whose owner is to be returned. Return Value The function returns the context owner's window handle if the passed arguments are valid. Otherwise, it returns NULL. Comments This function allows the tablet manager to coordinate tablet context manage¬ment with the states of the context-owning windows. 5.6.3 WTMgrDefContext Syntax HCTX WTMgrDefContext(hMgr, fSystem) This function retrieves a context handle that allows setting values for the current default digit¬izing or system context. Parameter Type/Description hMgr HMGR Is the valid manager handle that identifies the caller as a manager application. fSystem BOOL Specifies retrieval of the default system context if non-zero, or the default digitizing context if zero. Return Value The return value is the context handle for the specified default context, or NULL if the arguments were invalid. Comments The default digitizing context is the context whose attributes are returned by the WTInfo function WTI_DEFCONTEXT category. The default system context is the context whose attributes are returned by the WTInfo function WTI_DEFSYSCTX category. Editing operations on the retrieved handles will fail if the new default contexts do not meet certain requirements. The digitizing context must include at least buttons, x, and y in its packet data, and must return absolute coordinates. 1.1: Editing the current default digitizing context will also update the device-spe¬cific default context for the device listed in the lcDevice field of the default con¬text’s LOGCONTEXT structure. See Also The WTInfo function in section 5.1.1 the WTMgrDefContextEx function in section 5.6.4, and the category and index definitions in tables 7.3 through 7.9. 5.6.4 WTMgrDefContextEx (1.1) Syntax HCTX WTMgrDefContextEx(hMgr, wDevice, fSystem) This function retrieves a context handle that allows setting values for the default digit¬izing or system context for a specified device. Parameter Type/Description hMgr HMGR Is the valid manager handle that identifies the caller as a manager application. wDevice UINT Specifies the device for which a default context handle will be returned. fSystem BOOL Specifies retrieval of the default system context if non-zero, or the default digitizing context if zero. Return Value The return value is the context handle for the specified default context, or NULL if the arguments were invalid. Comments The default digitizing contexts are contexts whose attributes are returned by the WTInfo function WTI_DDCTXS multiplexed category. The default system con-texts are contexts whose attributes are returned by the WTInfo function WTI_DSCTXS multiplexed category. Editing operations on the retrieved handles will fail if the new default contexts do not meet certain requirements. The digitizing context must include at least buttons, x, and y in its packet data, and must return absolute coordinates. See Also The WTInfo function in section 5.1.1, and the category and index definitions in tables 7.3 through 7.9. 5.7 Manager Configuration Functions These functions allow manager applications to replace the default context configuration dialog and to display a configuration dialog for each hardware device. 5.7.1 WTMgrDeviceConfig Syntax UINT WTMgrDeviceConfig(hMgr, wDevice, hWnd) This function displays a custom modal tablet-hardware configuration dialog box, if one is supported. Parameter Type/Description hMgr HMGR Is the valid manager handle that identifies the caller as a manager application. wDevice UINT Identifies the device that the user will configure via the dialog box. hWnd HWND Identifies the window that will be the parent window of the dialog box. If this argument is NULL, the function will return non-zero if the dialog is supported, or zero otherwise. Return Value The return value is zero if the dialog box is not supported. Otherwise, it is one of the following non-zero values. Value Meaning WTDC_CANCEL The user canceled the dialog without making any changes. WTDC_OK The user made and confirmed changes. WTDC_RESTART The user made and confirmed changes that require a sys-tem restart in order to take effect. The calling program should query the user to determine whether to restart. Restart Windows using the function call ExitWin-dows(EW_RESTARTWINDOWS, 0);. 5.7.2 WTMgrConfigReplace (16-bit only) Syntax BOOL WTMgrConfigReplace(hMgr, fInstall, lpConfigProc) This function allows a manager application to replace the default behavior of the WTConfig function. Parameter Type/Description hMgr HMGR Is the valid manager handle that identifies the caller as a manager application. fInstall BOOL Specifies installation of a replacement function if non-zero, or removal of the current replacement if zero. lpConfigProc WTCONFIGPROC Is the procedure-instance address of the new configuration function. This argument is ignored during a re¬moval request. Return Value The function return non-zero if the installation or removal request succeeded. Oth-erwise, it returns zero. Comments This function is non-portable and is superseded by WTMgrConfigReplaceEx. See Also The WTConfig function in section 5.3.1, and for a description of the configuration callback function, see the WTMgrConfigReplaceEx function in section 5.7.3. 5.7.3 WTMgrConfigReplaceEx Syntax BOOL WTMgrConfigReplaceEx(hMgr, fInstall, lpszModule, lpszCfgProc) This function allows a manager application to replace the default behavior of the WTConfig function. Parameter Type/Description hMgr HMGR Is the valid manager handle that identifies the caller as a manager application. fInstall BOOL Specifies installation of a replacement function if non-zero, or removal of the current replacement if zero. lpszModule LPCTSTR Points to a null-terminated string that names a DLL module containing the new configuration function. This argument is ignored during a re¬moval request lpszCfgProc LPCSTR Points to a null-terminated string that names the new configuration function. This argument is ignored during a re¬moval request. Return Value The function return non-zero if the installation or removal request succeeded. Oth-erwise, it returns zero. Comments The configuration callback function must have attributes equivalent to WINAPI. Only one callback function may be installed at a time. The manager handle passed with the removal request must match the handle passed with the corre¬sponding in-stallation request. Tablet managers that install a replacement context configuration function must re-move it before exiting. Callback BOOL WINAPI ConfigProc(hWnd, hCtx) HWND hWnd; HCTX hCtx; ConfigProc is a place holder for the application-supplied function name. The actual name must be exported by including it in an EXPORTS statement in the applica-tion's module-definition file. Parameter Description hWnd Identifies the window that will be the parent window of the dialog box. hCtx Identifies the context that the user will modify via the dialog box. Return Value The function returns a non-zero value if the tablet context was changed, zero oth-erwise. Comments The configuration function and resulting dialog box should analyze the lcLocks context structure member, and only allow editing of unlocked context attributes. See Also The WTConfig function in section 5.3.1. 5.8 Manager Packet Hook Functions These functions allow manager applications to monitor, record, and play back sequences of tablet packets. 5.8.1 WTMgrPacketHook (16-bit only) Syntax WTHOOKPROC WTMgrPacketHook(hMgr, fInstall, nType, lpFunc) This function installs or removes a packet hook function. Parameter Type/Description hMgr HMGR Is the valid manager handle that identifies the caller as a manager application. fInstall BOOL Specifies installation of a hook function if non-zero, or removal of the specified hook if zero. nType int Specifies the packet hook to be installed. It can be any one of the following values: Value Meaning WTH_PLAYBACK Installs a packet playback hook. WTH_RECORD Installs a packet record hook. lpFunc WTHOOKPROC Is the procedure-instance address of the hook function to be installed. See the "Comments" section under WTMgrPacketHookEx for details. Return Value When installing a hook, the return value points to the procedure-instance ad¬dress of the previously installed hook (if any). It is NULL if there is no previous hook; it is negative one if the hook cannot be installed. The application or library that calls this func¬tion should save this return value in the library's data segment. The fourth argument of the WTPacketHookDefProc function points to the location in memory where the library saves this return value. When removing a hook, the return value is the passed lpFunc if successful, NULL otherwise. Comments This function is non-portable and is superseded by WTMgrPacketHookEx and WTMgrPacketUnhook. See Also the WTMgrPacketHookEx function in section 5.8.2, and the WTMgrPacketUn-hook function in section 5.8.3. 5.8.2 WTMgrPacketHookEx Syntax HWTHOOK WTMgrPacketHookEx(hMgr, nType, lpszModule, lpszHookProc) This function installs a packet hook function. Parameter Type/Description hMgr HMGR Is the valid manager handle that identifies the caller as a manager application. nType int Specifies the packet hook to be installed. It can be any one of the following values: Value Meaning WTH_PLAYBACK Installs a packet playback hook. WTH_RECORD Installs a packet record hook. lpszModule LPCTSTR Points to a null-terminated string that names a DLL module containing the new hook function. See the following "Comments" section for details. lpszHookProc LPCSTR Points to a null-terminated string that names the new hook function. See the following "Comments" section for details. Return Value If the function succeeds, the return value is the handle of the installed hook func-tion. Otherwise, the return value is NULL. Comments Packet hooks are a shared resource. Installing a hook affects all applications using the interface. All Wintab hook functions must be exported functions residing in a DLL module. The following section describes how to support the individual hook functions. WTH_PLAYBACK Wintab calls the WTH_PLAYBACK hook whenever a request for an event packet is made. The function is intended to be used to supply a previously recorded event packet for a compatible context. The hook function must have attributes equivalent to WINAPI. The filter function must have the following form: Hook Function LRESULT WINAPI HookFunc(nCode, wParam, lParam); int nCode; WPARAM wParam; LPARAM lParam; HookFunc is a place holder for the library-supplied function name. The actual name must be exported by including it in an EXPORTS statement in the library's mod¬ule-definition file. Parameter Description nCode Specifies whether the hook function should process the mes¬sage or call the WTMgrPacketHookDefProc (if installed by WTMgrPacketHook)or WTMgrPacketHookNext (if installed by WTMgrPacketHookEx) function. If the nCode parame¬ter is less than zero, the hook function should pass the message to the appropriate function without further process¬ing. wParam Specifies the context handle whose event is being requested. lParam Points to the packet being processed by the hook function. Comments The WTH_PLAYBACK function should copy an event packet to the buffer pointed to by the lParam pa¬rameter. The packet must have been previously recorded by us-ing the WTH_RECORD hook. It should not modify the packet. The return value should be the amount of time (in milliseconds) Wintab should wait before pro¬cess¬ing the mes¬sage. This time can be computed by calculation the difference between the time stamps of the current and previous packets. If the function returns zero, the message is processed immediately. Once it returns control to Wintab, the packet continues to be processed. If the nCode parameter is WTHC_SKIP, the hook func-tion should prepare to return the next recorded event message on its next call. The packet pointed to by lParam will have the same structure as packets re¬trieved from the context normally. Wintab will validate the following packet items to en¬sure consistency: context handle, time stamp, and serial number. The remaining fields will be valid if the context used for playback is equivalent to the context from which the events were recorded. The WTH_PLAYBACK hook will not be called to notify it of the display or re¬moval of system modal dialog boxes. It is expected that applications playing back packets will also be playing back window event messages using Windows' own hook functions. While the WTH_PLAYBACK function is in effect, Wintab ignores all hardware in-put. WTH_RECORD The interface calls the WTH_RECORD hook whenever it processes a packet from a context event queue. The hook can be used to record the packet for later playback. The hook function must have attributes equivalent to WINAPI. The hook function must have the following form: Hook Function LRESULT WINAPI HookFunc(nCode, wParam, lParam); int nCode; WPARAM wParam; LPARAM lParam; HookFunc is a place holder for the library-supplied function name. The actual name must be exported by including it in an EXPORTS statement in the library's mod¬ule-definition file. Parameter Description nCode Specifies whether the hook function should process the mes¬sage or call the WTMgrPacketHookDefProc (if installed by WTMgrPacketHook)or WTMgrPacketHookNext (if installed by WTMgrPacketHookEx) function. If the nCode parame¬ter is less than zero, the hook function should pass the message to the appropriate function without further process¬ing. wParam Specifies the context handle whose event is being processed. lParam Points to the packet being processed by the hook function. Comments The WTH_RECORD function should save a copy of the packet for later play¬back. It should not modify the packet. Once it returns control to Wintab, the message con-tinues to be processed. The filter function does not require a return value. The packet pointed to by lParam will have the same structure as packets re¬trieved from the context normally. The WTH_RECORD hook will not be called to notify it of the display or re¬moval of system modal dialog boxes. It is expected that applications recording packets will also be recording window event messages using Windows' own hook functions. 5.8.3 WTMgrPacketUnhook Syntax BOOL WTMgrPacketUnhook(hHook) This function removes a hook function installed by the WTMgrPacketHookEx function. Parameter Type/Description hHook HWTHOOK Identifies the hook function to be removed. Return Value The function returns a non-zero value if successful, zero otherwise. See Also The WTMgrPacketHookEx function in section 5.8.2, and the WTMgrPack-etHookNext function in section 5.8.5. 5.8.4 WTMgrPacketHookDefProc (16-bit only) Syntax LRESULT WTMgrPacketHookDefProc(nCode, wParam, lParam, lplpFunc) This function calls the next function in a chain of packet hook functions. A packet hook function is a function that processes packets before they are re¬trieved from a context's queue. When applications define more than one hook function by using the WTMgrPacketHook function, Wintab places func¬tions of the same type in a chain. Parameter Type/Description nCode int Specifies a code used by the hook function to determine how to process the message. wParam WPARAM Specifies the word parameter of the message that the hook function is processing. lParam LPARAM Specifies the long parameter of the message that the hook function is processing. lplpFunc WTHOOKPROC FAR * Points to a memory location that con-tains the WTHOOKPROC returned by the WTMgrPacketHook function. Wintab changes the value at this location after an appli-cation unhooks the hook using the WTMgrPacketHook function. Return Value The return value specifies a value that is directly related to the nCode parameter. Comments This function is non-portable and is superseded by the WTMgrPacketHookNext function. See Also The WTMgrPacketHookNext function in section 5.8.5. 5.8.5 WTMgrPacketHookNext Syntax LRESULT WTMgrPacketHookNext(hHook, nCode, wParam, lParam) This function passes the hook information to the next hook function in the current hook chain. Parameter Type/Description hHook HWTHOOK Identifies the current hook. nCode int Specifies the hook code passed to the current hook function. wParam WPARAM Specifies the wParam value

2,507

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 数据库相关
社区管理员
  • 数据库相关社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧