MySQL (libmysql) Question.

I'm using the MySQL Connection library (libmysql.dll) to establish a connection to my SQL server. Everything worked fine until I decided to allow the user to input the server info themselves then passing that info to the mysql_real_connect() function using WINAPI with WM_COMMAND case. The program compiles correctly but breaks after entering the info and hitting Connect. I have quite a bit of code so I'll try to provide what I think is essentials. If you need the full code then please ask and I'll provide it.

Defining my controls:
1
2
3
4
5
6
7
8
9
10
11
12
#define IDC_SERVER_LABEL   2000
#define IDC_SERVER_EDIT    2005
#define IDC_PORT_LABEL     2010
#define IDC_PORT_EDIT      2015
#define IDC_DB_LABEL       2020
#define IDC_DB_EDIT        2025
#define IDC_USER_LABEL     2030
#define IDC_USER_EDIT      2035
#define IDC_PASSWORD_LABEL 2040
#define IDC_PASSWORD_EDIT  2045
#define IDC_LOGIN_BUTTON   2050
#define IDC_EXIT_BUTTON    2055 


WM_CREATE case:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
	case WM_CREATE:
	{
		HINSTANCE hIns;
		hIns = ((LPCREATESTRUCT)lParam)->hInstance;
		CreateWindowEx(NULL, L"Static", L"Server: ", WS_CHILD | WS_VISIBLE, 10, 20, 75, 20, hWnd, (HMENU)IDC_SERVER_LABEL, hIns, NULL);
		CreateWindowEx(NULL, L"Edit", NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 100, 20, 150, 20, hWnd, (HMENU)IDC_SERVER_EDIT, hIns, NULL);

		CreateWindowEx(NULL, L"Static", L"Port: ", WS_CHILD | WS_VISIBLE, 10, 50, 75, 20, hWnd, (HMENU)IDC_PORT_LABEL, hIns, NULL);
		CreateWindowEx(NULL, L"Edit", NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 100, 50, 150, 20, hWnd, (HMENU)IDC_PORT_EDIT, hIns, NULL);

		CreateWindowEx(NULL, L"Static", L"DB Name: ", WS_CHILD | WS_VISIBLE, 10, 80, 75, 20, hWnd, (HMENU)IDC_DB_LABEL, hIns, NULL);
		CreateWindowEx(NULL, L"Edit", NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 100, 80, 150, 20, hWnd, (HMENU)IDC_DB_EDIT, hIns, NULL);

		CreateWindowEx(NULL, L"Static", L"Username: ", WS_CHILD | WS_VISIBLE, 10, 110, 75, 20, hWnd, (HMENU)IDC_USER_LABEL, hIns, NULL);
		CreateWindowEx(NULL, L"Edit", NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 100, 110, 150, 20, hWnd, (HMENU)IDC_USER_EDIT, hIns, NULL);

		CreateWindowEx(NULL, L"Static", L"Password: ", WS_CHILD | WS_VISIBLE, 10, 140, 75, 20, hWnd, (HMENU)IDC_PASSWORD_LABEL, hIns, NULL);
		CreateWindowEx(NULL, L"Edit", NULL, WS_CHILD | ES_PASSWORD | WS_VISIBLE | WS_TABSTOP, 100, 140, 150, 20, hWnd, (HMENU)IDC_PASSWORD_EDIT, hIns, NULL);

		CreateWindowEx(NULL, L"Button", L"Connect", WS_CHILD | WS_VISIBLE, 100, 170, 90, 25, hWnd, (HMENU)IDC_LOGIN_BUTTON, hIns, NULL);
		CreateWindowEx(NULL, L"Button", L"Exit", WS_CHILD | WS_VISIBLE, 200, 170, 50, 25, hWnd, (HMENU)IDC_EXIT_BUTTON, hIns, NULL);
		SetFocus(GetDlgItem(hWnd, IDC_SERVER_EDIT));

		return 0;
	}


WM_COMMAND case:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
	case WM_COMMAND:
	{
		switch (LOWORD(wParam))
		{
		case IDC_LOGIN_BUTTON:
		{
			const char *host = GetDlgItem(hWnd, IDC_SERVER_EDIT);
			const char *user = GetDlgItem(hWnd, IDC_USER_EDIT);
			const char *pass = GetDlgItem(hWnd, IDC_PASSWORD_EDIT);
			const char *dbname = GetDlgItem(hWnd, IDC_DB_EDIT);
			UINT port = GetDlgItem(hWnd, IDC_PORT_EDIT);
			const char *unix_socket = NULL;

			UINT flag = 0;

			MYSQL *conn;
			conn = mysql_init(NULL);

			if (mysql_real_connect(conn, host, user, pass, dbname, port, unix_socket, flag))
			{
				MessageBox(NULL, L"Connection Established", L"Connect", MB_OK | MB_ICONERROR);
			}
			else
			{
				MessageBox(NULL, L"Connection Failed", L"Connection Failed", MB_OK | MB_ICONERROR);
			}
		}
			break;
		case IDC_EXIT_BUTTON:
			DestroyWindow(hWnd);
			break;
		}
		return 0;
	}
Last edited on
This shouldn't even compile. See:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms645481%28v=vs.85%29.aspx

GetDlgItem(...) returns HWND which a handle to the window you created in WM_CREATE.


Use GetDlgItemText(...) instead:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms645489%28v=vs.85%29.aspx
@coder777

I tried your suggestion with this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
		case IDC_LOGIN_BUTTON:
		{
			char temp[50];

			const char *host = GetDlgItemText(NULL, IDC_SERVER_EDIT, temp, 50);
			const char *user = GetDlgItemText(NULL, IDC_USER_EDIT, temp, 50);
			const char *pass = GetDlgItemText(NULL, IDC_PASSWORD_EDIT, temp, 50);
			const char *dbname = GetDlgItemText(NULL, IDC_DB_EDIT, temp, 50);
			UINT port = GetDlgItemText(NULL, IDC_PORT_EDIT, temp, 50);
			const char *unix_socket = NULL;

			UINT flag = 0;

			MYSQL *conn;
			conn = mysql_init(NULL);

			if (mysql_real_connect(conn, host, user, pass, dbname, port, unix_socket, flag))
			{
				MessageBox(NULL, L"Connection Established", L"Connect", MB_OK | MB_ICONERROR);
			}
			else
			{
				MessageBox(NULL, L"Connection Failed", L"Connection Failed", MB_OK | MB_ICONERROR);
			}
		}
			break;


Now it goes ahead with the "Connection Established" message box even when the inserted information is wrong, or no information at all is entered.
Last edited on
Please read the documentation carefully:
MSDN wrote:
Return value

Type: UINT

If the function succeeds, the return value specifies the number of characters copied to the buffer, not including the terminating null character.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

GetDlgItemText(...) does not return a string either. temp is supposed to be host, user, etc.


Unfortunately it is not quite clear what the function retrievs exactly:
MSDN wrote:
Retrieves the title or text associated with a control in a dialog box.
So check the content. I would think it is your edited text.
Hmmm alright. Still trying to make sense of it all. I have the window handle needed, the ID of the control I'm trying to extract info from, and a buffer to write to. Not sure what else it could be.
Last edited on
It is supposed to look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
case IDC_LOGIN_BUTTON:
		{
			char host[50];
			char user[50];

			UINT result_host = GetDlgItemText(NULL, IDC_SERVER_EDIT, host, sizeof(host));
			UINT result_user = GetDlgItemText(NULL, IDC_USER_EDIT, user, sizeof(user));

if((result_host > 0) && (result_user > 0))
{
			if (mysql_real_connect(conn, host, user, pass, dbname, port, unix_socket, flag))
...
}
...
Note that you pass NULL as the first parameter. It should be the hWnd.
Last edited on
I feel like I'm getting closer as it quit breaking, but constantly get the "failed connection" message box when all the proper info is given. It's as though it's passing the values incorrectly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
		case IDC_LOGIN_BUTTON:
		{
			char host[50];
			char user[50];
			char pass[50];
			char dbname[50];
			char port[50];

			UINT result_host = GetDlgItemText(hWnd, IDC_SERVER_EDIT, host, sizeof(host));
			UINT result_user = GetDlgItemText(hWnd, IDC_USER_EDIT, user, sizeof(user));
			UINT result_pass = GetDlgItemText(hWnd, IDC_PASSWORD_EDIT, pass, sizeof(pass));
			UINT result_dbname = GetDlgItemText(hWnd, IDC_DB_EDIT, dbname, sizeof(dbname));
			UINT result_port = GetDlgItemText(hWnd, IDC_PORT_EDIT, port, sizeof(port));
			const char *unix_socket = NULL;

			UINT flag = 0;

			MYSQL *conn;
			conn = mysql_init(NULL);

			if ((result_host > 0) && (result_user > 0))
			{
				if (mysql_real_connect(conn, host, user, pass, dbname, port, unix_socket, flag))
				{
					MessageBox(NULL, L"Connection Established", L"Success", MB_OK | MB_ICONERROR);
				}
				else
				{
					MessageBox(NULL, L"Connection Failed", L"Connection Failed", MB_OK | MB_ICONERROR);
				}
			}
			else
			{
				MessageBox(NULL, L"All fields must be filled", L"Error", MB_OK | MB_ICONERROR);
			}
		}
The mysql_real_connect(...) parameter port is not string. It is actually int.

See:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms645485%28v=vs.85%29.aspx

how to get an int from a text box.

Otherwise you need to convert the string yourself to int (like atoi).

See atoi:
http://www.cplusplus.com/reference/cstdlib/atoi/?kw=atoi
Well I'm still messing with this trying to get it to work. Instead of learning a few new calls such as atoi I figured I would hard code in the port just to get a connection success and it's still returning the "Connection Failed" messagebox. I've tried the same code in a console app just printing out success or failure with the same server credentials and it seems to work fine. Only seems to fail out when integrating it into my WINAPI code. Here is the updated case statement with the hard coded port number.

When setting a break point after the info is entered and submitted it seems to store the information as an integer. I check for the value of "port" and it shows "3306" which is correct. but if I check for say the value of "result_host" or "result_user" its a number So instead of its value being "localhost" its value is stored as "9"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
		case IDC_LOGIN_BUTTON:
		{
			static char host[50];
			static char user[50];
			static char pass[50];
			static char dbname[50];
			//static int port[50];

			UINT result_host = GetDlgItemText(hWnd, IDC_SERVER_EDIT, host, sizeof(host));
			UINT result_user = GetDlgItemText(hWnd, IDC_USER_EDIT, user, sizeof(user));
			UINT result_pass = GetDlgItemText(hWnd, IDC_PASSWORD_EDIT, pass, sizeof(pass));
			UINT result_dbname = GetDlgItemText(hWnd, IDC_DB_EDIT, dbname, sizeof(dbname));
			//UINT result_port = GetDlgItemInt(hWnd, IDC_PORT_EDIT, port, FALSE);
			const char *unix_socket = NULL;

			UINT flag = 0;
			UINT port = 3306;

			MYSQL *conn;
			conn = mysql_init(NULL);

			if ((result_host > 0) && (result_user > 0) && (result_pass > 0) && (result_dbname > 0))
			{
				if (mysql_real_connect(conn, host, user, pass, dbname, port, unix_socket, flag))
				{
					MessageBox(NULL, L"Connection Established", L"Success", MB_OK | MB_ICONERROR);
				}
				else
				{
					MessageBox(NULL, L"Connection Failed", L"Connection Failed", MB_OK | MB_ICONERROR);
				}
			}
			else
			{
				MessageBox(NULL, L"All fields must be filled", L"Error", MB_OK | MB_ICONERROR);
			}
		}
Last edited on
Even more odd is that when I dont put in any information and hit the connect (IDC_LOGIN_BUTTON) it returns the "Connection Established" message box. How is that even possible if it's not processing a valid mysql_real_connect()?
So instead of its value being "localhost" its value is stored as "9"
9 is the size of string "localhost". That is what the function returns: The length of the string.

You prepend each string with L. This means UNICODE (2 bytes per character). I would guess that mysql_real_connect(...) expect something like ASCII. You can get this with GetDlgItemTextA(...) (notice the A).

How come that it compiles? GetDlgItemText(...) is supposed to expect wchar * not char *
Alright after hours of trial and error, and then more hours of research and more reading I've learned that the passed values need to be converted from Unicode to ASCII as mysql_real_connect requires it. Here is the new working code in case this ever comes up in a search. I'm sure I can wrap the conversion process into a function for re usability, I'll work on that next. If someone wants to help, feel free to :)

new code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
		case IDC_LOGIN_BUTTON:
		{
			static wchar_t host[50];
			static wchar_t user[50];
			static wchar_t pass[50];
			static wchar_t dbname[50];

			static char newHost[50];
			static char newUser[50];
			static char newPass[50];
			static char newDBname[50];
			static char newPort[50];

			UINT resultHost = GetDlgItemText(hWnd, IDC_SERVER_EDIT, host, sizeof(host));
			UINT resultUser = GetDlgItemText(hWnd, IDC_USER_EDIT, user, sizeof(user));
			UINT resultPass = GetDlgItemText(hWnd, IDC_PASSWORD_EDIT, pass, sizeof(pass));
			UINT resultDB = GetDlgItemText(hWnd, IDC_DB_EDIT, dbname, sizeof(dbname));

			WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, host, -1, newHost, 50, NULL, NULL);
			WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, user, -1, newUser, 50, NULL, NULL);
			WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pass, -1, newPass, 50, NULL, NULL);
			WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, dbname, -1, newDBname, 50, NULL, NULL);

			const char *unix_socket = NULL;

			MYSQL *conn;
			UINT flag = 0;
			UINT port = 3306;

			conn = mysql_init(NULL);

			if ((resultHost > 0) && (resultUser > 0) && (resultPass > 0) && (resultDB > 0))
			{

				if (!mysql_real_connect(conn, newHost, newUser, newPass, newDBname, port, unix_socket, flag))
				{
					MessageBox(NULL, L"Connection Failed", L"Connection Failed", MB_OK | MB_ICONERROR);
				}
				else
				{
					MessageBox(NULL, L"Connection Established", L"Success", MB_OK | MB_ICONINFORMATION);
				}
			}
			else
			{
				MessageBox(NULL, L"Missing information", L"Error", MB_OK | MB_ICONERROR);
			}

		} break;
Again: If you'd use the GetDlgItemTextA variant you wouldn't need the conversion.
@coder777 I tried that solution and it did nothing for me.
Topic archived. No new replies allowed.