Win32 API programming with C - Working with the database

Ciprian FusaCiprian Fusa
3 min read

The Microsoft Open Database Connectivity (ODBC) interface is a C programming language interface that makes it possible for applications to access data from a variety of database management systems (DBMSs). ODBC is a low-level, high-performance interface that is designed specifically for relational data stores.

In the previous article, we saved the text from our Edit control to a .txt file on disk, in this article we will see how we can save that text to the database.

Prerequisites

Here's what we will need for this:

  • SQL Server or SQL Server Express installed and accessible.

  • ODBC drivers for SQL Server installed.

  • An ODBC Data Source Name (DSN) configured for the database we intend to connect to. Let's assume the DSN is named MySqlServerDsn.

  • The Win32 Development Tools and SDK installed.

How to add a new ODBC data source

We will add a new ODBC data source named MySqlServerDsn.

Open ODBC data source administrator and click Add.

Choose SQL Server and click Finish.

Enter the Name and SQL Server instance you want to connect to.

Choose Windows or SQL Server authentication and click Next.

Choose default database and click Next and Finish. Click Test Data Source to make sure everything is ok.

Once we have our DSN we can start writing code to connect to our database. For the purpose of this article I have added a new database called MyDatabase and a new table called Articles which look like this:

We need to include necessary headers and link against required libraries. Add this at the top of your source file.

#include <sql.h>
#include <sqlext.h>
#pragma comment (lib, "odbc32.lib")

Define global variables

SQLHENV env;              // environment handle
SQLHDBC dbc;              // connection handle
SQLHSTMT stmt;            // statement handle
SQLRETURN ret;              // ODBC API return status

Write save to database method

BOOL SaveToDatabase(HWND hEdit, HWND hwnd)
{
    // Allocate an environment handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
    // Set the ODBC version environment attribute
    SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
    // Allocate a connection handle
    SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
    // Connect to the DSN
    SQLDriverConnect(dbc, NULL, (SQLCHAR*)"DSN=MySqlServerDsn;", SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
    // Allocate a statement handle
    SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);

    // Preparing an INSERT SQL statement
    char* sqlInsert = "INSERT INTO dbo.Articles(Id, Text) VALUES (?,?);";
    SQLPrepare(stmt, (SQLCHAR*)sqlInsert, SQL_NTS);

    // prepare parameters
    SQLINTEGER id = 1;
    SQLCHAR articleText[256];   // size as needed
    strcpy(articleText, ReadTextFromEdit(hEdit));

    // Bind parameters
    SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &id, 0, NULL);
    SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(articleText), 0, articleText, 0, NULL);

    // Execute the statement
    ret = SQLExecute(stmt);
    if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
        MessageBox(hwnd, "Record inserted successfully.", "Success", MB_OK | MB_ICONINFORMATION);
    }
    else {
        MessageBox(hwnd, "Error executing sql statement.", "Error", MB_OK | MB_ICONERROR);
    }

    // Clean up
    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
    SQLDisconnect(dbc);
    SQLFreeHandle(SQL_HANDLE_DBC, dbc);
    SQLFreeHandle(SQL_HANDLE_ENV, env);
}

Modify our Window Procedure code so when we click the button we call this method instead of opening the file save dialog.

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        // ...
        case WM_COMMAND:
            switch (LOWORD(wParam)) {
                case ID_MYBUTTON:
                    HWND hEdit = GetDlgItem(hwnd, IDC_MY_EDIT);
                    SaveToDatabase(hEdit, hwnd);
                    break;
            break;
        // ...
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
        }
    return 0;
}
0
Subscribe to my newsletter

Read articles from Ciprian Fusa directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ciprian Fusa
Ciprian Fusa

I am a .NET Developer and Consultant with over 15 years of experience, I specialize in crafting scalable, high-performance applications that drive business growth and innovation.