📄 odbc5.html
字号:
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
invoke SQLExecDirect, hStmt, addr SQLStatement, sizeof SQLStatement
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
invoke FillData
.else
invoke ShowWindow, hList, SW_HIDE
invoke MessageBox,hDlg,addr ExecuteFail, addr AppName, MB_OK+MB_ICONERROR
.endif
invoke SQLCloseCursor, hStmt
invoke SQLFreeHandle, SQL_HANDLE_STMT, hStmt
.else
invoke ShowWindow, hList, SW_HIDE
invoke MessageBox,hDlg,addr AllocStmtFail, addr AppName, MB_OK+MB_ICONERROR
.endif
ret
RunQuery endp
QueryProc proc hDlg:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
.if uMsg==WM_CLOSE
invoke SQLFreeHandle, SQL_HANDLE_STMT, hStmt
invoke EndDialog, hDlg,0
.elseif uMsg==WM_INITDIALOG
invoke ShowWindow, hList, SW_SHOW
invoke SQLAllocHandle, SQL_HANDLE_STMT, hConn, addr hStmt
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
invoke lstrcpy, addr Conn, addr SQLStatement
invoke lstrcat, addr Conn, addr WhereStatement
invoke SQLBindParameter,hStmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,25,0, addr SearchName,25,addr StrLen
invoke SQLPrepare, hStmt, addr Conn, sizeof Conn
.else
invoke ShowWindow, hList, SW_HIDE
invoke MessageBox,hDlg,addr AllocStmtFail, addr AppName, MB_OK+MB_ICONERROR
invoke EndDialog, hDlg,0
.endif
.elseif uMsg==WM_COMMAND
mov eax, wParam
shr eax,16
.if ax==BN_CLICKED
mov eax,wParam
.if ax==IDC_OK
invoke GetDlgItemText, hDlg, IDC_NAME, addr SearchName, 25
.if ax==0
invoke MessageBox, hDlg,addr NoData, addr AppName, MB_OK+MB_ICONERROR
invoke GetDlgItem, hDlg, IDC_NAME
invoke SetFocus, eax
.else
invoke lstrlen,addr SearchName
mov StrLen,eax
invoke SendMessage, hList, LVM_DELETEALLITEMS,0,0
invoke SQLExecute, hStmt
invoke FillData
invoke SQLCloseCursor, hStmt
.endif
.else
invoke SQLFreeHandle, SQL_HANDLE_STMT, hStmt
invoke EndDialog, hDlg,0
.endif
.endif
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
QueryProc endp
end start</b></font>
</pre>
<h4><font face="Tahoma" color="#FFFFCC">Analysis</font></h4>
<pre><b><font face="Tahoma" color="#33CCCC">start:
invoke GetModuleHandle, NULL
mov hInstance,eax
call GetProgramPath</font></b></pre>
<p><font face="Tahoma" size="-1">When the program starts, it obtains the instance
handle and then finds out its own path. The assumption is that the database,
test.mdb, would be in the same folder as the program. </font><br>
</p>
<pre><font face="Tahoma"><b><font color="#33CCCC">GetProgramPath proc
invoke GetModuleFileName, NULL,addr ProgPath,sizeof ProgPath
std
mov edi,offset ProgPath
add edi,sizeof ProgPath-1
mov al,"\"
mov ecx,sizeof ProgPath
repne scasb
cld
mov byte ptr [edi+2],0
ret
GetProgramPath endp</font></b></font> </pre>
<p><font face="Tahoma" size="-1">GetProgramPath calls GetModuleFileName to obtain
the full pathname of the program. After that, it searchs for the last "\"
in the pathname so that it can "truncate" the filename from the path
by replacing the first character of the filename with 0. Thus we got the path
of the program in ProgPath.</font></p>
<p><font face="Tahoma" size="-1">The program then displays the main dialog box
with <font color="#FFFFCC"><b>DialogBoxParam</b></font>. The first time the
main dialog box is loaded, it obtains the menu handle and the handle to the
listview control. It next inserts three columns into the listview control (because
we know beforehand that the result set consists of three columns. After all
we are the one who created the table in the first place.)</font></p>
<p><font face="Tahoma" size="-1">After that, it waits for the user's action. If
the user selects "connect" from the menu, it calls <font color="#FFFFCC"><b>ODBCConnect</b></font>
function.</font></p>
<pre><font face="Tahoma"><b><font color="#33CCCC">ODBCConnect proc hDlg:DWORD
invoke SQLAllocHandle, SQL_HANDLE_ENV, SQL_NULL_HANDLE, addr hEnv
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO</font></b></font></pre>
<p><font face="Tahoma"><font size="-1">The first thing it does is to allocate
an environment handle with <font color="#FFFFCC"><b>SQLAllocHandle</b></font>.</font><b><font color="#33CCCC"><br>
</font></b></font></p>
<pre><font face="Tahoma"><b><font color="#33CCCC"> invoke SQLSetEnvAttr, hEnv,SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3,0
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO</font></b></font></pre>
<p><font face="Tahoma"><font size="-1">After it obtained the environment handle,
it specifies that it wants to use ODBC 3.x syntax by calling <font color="#FFFFCC"><b>SQLSetEnvAttr</b></font>.</font><b><font color="#33CCCC"><br>
</font></b></font></p>
<pre><font face="Tahoma"><b><font color="#33CCCC"> invoke SQLAllocHandle, SQL_HANDLE_DBC, hEnv, addr hConn
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO</font></b></font></pre>
<p><font face="Tahoma"><font size="-1">If all goes well, it can begin the connection
attempt by allocating a connection handle with <font color="#FFFFCC"><b>SQLAllocHandle</b></font>.</font><b><font color="#33CCCC"><br>
</font></b></font></p>
<pre><font face="Tahoma"><b><font color="#33CCCC"> invoke lstrcpy,addr ConnectString,addr strConnect
invoke lstrcat,addr ConnectString, addr ProgPath
invoke lstrcat, addr ConnectString,addr DBName</font></b></font></pre>
<p><font face="Tahoma"><font size="-1">Con</font><font size="-1">struct the connection
string. The final connection string we will use is in ConnectionString </font><b><font color="#33CCCC"><br>
</font></b></font></p>
<pre><font face="Tahoma"><b><font color="#33CCCC"> invoke SQLDriverConnect, hConn, hDlg, addr ConnectString, sizeof ConnectString, addr Conn, sizeof Conn,addr StrLen, SQL_DRIVER_COMPLETE
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
invoke SwitchMenuState,TRUE
invoke MessageBox,hDlg, addr Conn,addr ConnectCaption,MB_OK+MB_ICONINFORMATION</font></b></font></pre>
<p><font face="Tahoma"><font size="-1">When the connection string is ready, it
calls <font color="#FFFFCC"><b>SQLDriverConnect</b></font> to attempt to connect
to test.mdb with MS Access ODBC driver. If test.mdb is not found, the ODBC driver
will prompt the user for its location because we specify <font color="#CCFFCC"><b>SQL_DRIVER_COMPLETE</b></font>
flag. When SQLDriverConnect returned successfully, Conn is filled with the complete
connection string constructed by the ODBC driver. We display that string to
the user with a message box. SwitchMenuState is a simple function that enables/grays
out the appropriate menu items.</font></font></p>
<p><font face="Tahoma" size="-1">Right now, the connection to the database is
open until the user chooses to close it. </font></p>
<p><font face="Tahoma" size="-1">When the user selects "View All Records",
the dialog box procedure calls RunQuery.</font><font face="Tahoma"><b><font color="#33CCCC">
<br>
</font></b></font></p>
<pre><font face="Tahoma"><b>
<font color="#33CCCC">RunQuery proc hDlg:DWORD
invoke ShowWindow, hList, SW_SHOW
invoke SendMessage, hList, LVM_DELETEALLITEMS,0,0</font></b></font></pre>
<p><font face="Tahoma">Since the listview control is created hidden, it's now
the time to show it. Also we need to delete all items (if any) from the listview
control.<b><font color="#33CCCC"><br>
</font></b></font></p>
<pre><font face="Tahoma"><b><font color="#33CCCC"> invoke SQLAllocHandle, SQL_HANDLE_STMT, hConn, addr hStmt
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO</font></b></font></pre>
<p><font face="Tahoma"><font size="-1">Next, the program allocates a statement
handle. </font><b><br>
<font color="#33CCCC"> </font></b></font></p>
<pre><font face="Tahoma"><b><font color="#33CCCC"> invoke SQLExecDirect, hStmt, addr SQLStatement, sizeof SQLStatement
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO</font></b></font></pre>
<p><font face="Tahoma"><font size="-1">Execute the premade SQL statement with
<font color="#FFFFCC"> <b>SQLExecDirect</b></font>. I choose to use <font color="#FFFFCC"><b>SQLExecDirect</b></font>
here because thiis SQL statement is usually called only once.</font><b><font color="#33CCCC"><br>
</font></b></font></p>
<pre><font face="Tahoma"><b><font color="#33CCCC"> invoke FillData</font></b></font></pre>
<p><font face="Tahoma"><font size="-1">After executing the SQL statement, a result
set should be returned. We extract the data in the result set into the listview
control in FillData function.</font></font></p>
<pre><font face="Tahoma"><font face="Tahoma"><b><font color="#33CCCC">FillData proc
LOCAL lvi:LV_ITEM
LOCAL row:DWORD
invoke SQLBindCol, hStmt,1,SQL_C_CHAR, addr TheName, sizeof TheName,addr NameLength
invoke SQLBindCol, hStmt,2,SQL_C_CHAR, addr TheSurname, sizeof TheSurname,addr SurnameLength
invoke SQLBindCol, hStmt,3,SQL_C_CHAR, addr TelNo, sizeof TelNo,addr TelNoLength</font></b></font></font></pre>
<p><font face="Tahoma"><font face="Tahoma" size="-1">Here, the result set is returned.
We need to bind all three columns of the result set to the buffers we provided.
We call <font color="#FFFFCC"><b>SQLBindCol</b></font> to do that. Note that
we need a separate call for each column. And we need not bind ALL columns: only
the columns we need to obtain the data from. </font><font face="Tahoma"><b><br>
</b></font></font></p>
<pre><font face="Tahoma"><font face="Tahoma"><b><font color="#33CCCC"> mov row,0
.while TRUE
mov byte ptr ds:[TheName],0
mov byte ptr ds:[TheSurname],0
mov byte ptr ds:[TelNo],0</font></b></font></font></pre>
<p><font face="Tahoma"><font face="Tahoma" size="-1">We initialize the buffers
to NULLs in case there is no data in the column(s). The better way is to use
the length of data returned in the variables you specified in <font color="#FFFFCC"><b>SQLBindCol</b></font>.
In our example, we could check the values in <font color="#CCFFCC"><b>NameLength</b></font>,
<font color="#CCFFCC"> <b>SurnameLength</b></font> and <font color="#CCFFCC"><b>TelNoLength</b></font>
for the actual length of the strings returned.</font><font face="Tahoma"><b>
</b></font></font></p>
<pre><font face="Tahoma"><font face="Tahoma"><b><font color="#33CCCC"> invoke SQLFetch, hStmt
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
mov lvi.imask,LVIF_TEXT+LVIF_PARAM
push row
pop lvi.iItem
mov lvi.iSubItem,0
mov lvi.pszText, offset TheName
push row
pop lvi.lParam
invoke SendMessage,hList, LVM_INSERTITEM,0, addr lvi</font></b></font><font size="-1" color="#33CCCC"> </font><font color="#33CCCC"><b> </b></font></font></pre>
<p><font face="Tahoma"><font size="-1">The rest is simple. Call <font color="#FFFFCC"><b>SQLFetch
</b></font>to retrieve a row from the result set and then store the values in
the buffers into the listview control. When no more row is available (we have
reached the end of file), <font color="#FFFFCC"><b>SQLFetch</b></font> returns
<font color="#CCFFCC"><b>SQL_NO_DATA</b></font> and we exit the infinite loop.</font></font><font face="Tahoma"><b><font color="#33CCCC">
</font></b></font></p>
<pre><font face="Tahoma"><b><font color="#33CCCC"> invoke SQLCloseCursor, hStmt
invoke SQLFreeHandle, SQL_HANDLE_STMT, hStmt</font></b></font></pre>
<p><font face="Tahoma"><font size="-1">When we are done with the result set, we
must close it with <font color="#FFFFCC"><b>SQLCloseCursor</b></font> and then
free the statement handle with <font color="#FFFFCC"><b>SQLFreeHandle</b></font>.</font><font face="Tahoma" size="-1"><font color="#33CCCC"><br>
</font></font><font color="#33CCCC" face="Tahoma" size="-1"><br>
</font><font face="Tahoma" size="-1">When the user selects "Query"
menu item, the program displays another dialog box prompting the user for the
name to search for.</font></font></p>
<pre><font face="Tahoma"><b><font color="#33CCCC"> .elseif uMsg==WM_INITDIALOG
invoke ShowWindow, hList, SW_SHOW
invoke SQLAllocHandle, SQL_HANDLE_STMT, hConn, addr hStmt
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
invoke lstrcpy, addr Conn, addr SQLStatement
invoke lstrcat, addr Conn, addr WhereStatement
invoke SQLBindParameter,hStmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,25,0, addr SearchName,25,addr StrLen
invoke SQLPrepare, hStmt, addr Conn, sizeof Conn</font></b></font></pre>
<p><font face="Tahoma" size="-1">The first thing the dialog box does is to show
the listview control. It then allocates a statement handle, create an SQL statement.
This SQL statement has the "where" clause with a parameter marker,?.
The full SQL statement is:</font></p>
<blockquote>
<p><font face="Tahoma"><b>select * from main where name=?</b></font></p>
</blockquote>
<p><font size="-1" face="Tahoma">Next, it calls <font color="#FFFFCC"><b>SQLBindParameter</b></font>
to associate the parameter marker with the buffer, <font color="#CCFFCC"><b>SearchName</b></font>,
so that when the SQL statement is executed, the ODBC driver can obtain the string
it needs to use from <font color="#CCFFCC"><b>SearchName</b></font>. Afer that,
it calls <font color="#FFFFCC"><b>SQLPrepare</b></font> to compile the SQL statement.
The rationale is that, you prepare/compile the SQL statement only once and then
you execute it many times. Since the SQL statement was compiled, the subsequent
execution is faster.</font></p>
<pre><font face="Tahoma"><b><font color="#33CCCC"> .if ax==IDC_OK
invoke GetDlgItemText, hDlg, IDC_NAME, addr SearchName, 25
.if ax==0
invoke MessageBox, hDlg,addr NoData, addr AppName, MB_OK+MB_ICONERROR
invoke GetDlgItem, hDlg, IDC_NAME
invoke SetFocus, eax
.else</font></b></font></pre>
<p><font face="Tahoma"><font size="-1">When the user typed some name in the edit
control and pressed return key, the program retrieves the text from the edit
control and checks if it's a NULL string. If so, it displays a message box and
sets the keyboard focus to the edit control to prompt the user for a name.<br>
</font><b> </b></font></p>
<pre><font face="Tahoma"><b><font color="#33CCCC"> invoke lstrlen,addr SearchName
mov StrLen,eax
invoke SendMessage, hList, LVM_DELETEALLITEMS,0,0
invoke SQLExecute, hStmt
invoke FillData
invoke SQLCloseCursor, hStmt</font></b></font></pre>
<p><font face="Tahoma" size="-1">If a name is typed into the edit control, we
find out its length and store the value into <font color="#CCFFCC"><b>StrLen</b></font>
for use by ODBC driver (remember that we passed the address of StrLen to <font color="#FFFFCC"><b>SQLBindParameter</b></font>).
Then it calls <font color="#FFFFCC"><b>SQLExecute</b></font> on the statement
handle to execute the prepared SQL statement. When<font color="#FFFFCC"><b>
SQLExecute</b></font> returns, it calls FillData to display the result in the
listview control. Since we have no use for the result set anymore, we close
it by calling <font color="#FFFFCC"><b>SQLCloseCursor</b></font>.</font></p>
<hr>
<p align="center"><font face="Tahoma" size="-1"><b>[<a href="http://win32asm.cjb.net">Iczelion's
Win32 Assembly Homepage</a>]</b></font></p>
<p> </p>
<p> </p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -