• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 618
  • Last Modified:

Code Help - Reading registry and building querystring

Hi All,

I have been coding in C# for the last 5 years and have only saw my first bit of C++ code a few days ago. I have been assigned to modify a small piece of C++ code for a customer.  I have been struggling with some C++ concepts and require some assistance...

I'm not sure what the project type is, but it outputs a DLL which installs a custom IE button on your toolbar. Once this custom button is clicked, it will navigate to "https://www.mybank.com.tw/myatm/myatmkey_myatm.asp". The code that I must modify, is to read a registry key and append the value to the end of the URL - Example: "https://www.mybank.com.tw/myatm/myatmkey_myatm.asp?SessionID=2345678911CD".

I've managed to piece together the code to do this and it works (see code snippet for main cpp file). I've also attached the cpp file and the registry export.

On a colleague's machine, clicking on the button the first time executes perfectly. Then after that, we get a "SessionID=0", meaning that reading the registry has failed. Now I want to get a more specific error message of why it failed because the registry key still exists.

How can I get the error message returned from "RegOpenKeyEx" (I've tried to just add the error message to the querystring or use MessageBox) if the "result != ERROR_SUCCESS"?

I know this may take some time to look at the code, so thanks in advance!

Regards,
D


// MyBankApp.cpp : Implementation of MyBankApp
#include "stdafx.h"
#include "MyBankButton.h"
#include "MyBankApp.h"

/////////////////////////////////////////////////////////////////////////////
// MyBankApp

const TCHAR g_WWURL[]	= _T("https://www.mybank.com.tw/myatm/myatmkey_myatm.asp?SessionID=");

STDMETHODIMP MyBankApp::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
{
	// TODO: Add your implementation code here
	HRESULT hr = E_POINTER;

	if ( prgCmds != NULL)
	{
		for ( ULONG i = 0; i < cCmds; i++)
			prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED; 
		
		hr = S_OK;
	}
	return hr;	
//	return S_OK;
}

STDMETHODIMP MyBankApp::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
{
 	HRESULT hr = OLECMDERR_E_UNKNOWNGROUP;

	if ( pguidCmdGroup == NULL)
	{
		if ( nCmdID != 0)
			hr = OLECMDERR_E_NOTSUPPORTED;
		else
		{
			if ( nCmdexecopt == OLECMDEXECOPT_SHOWHELP)
			{
				hr = OLECMDERR_E_NOHELP;
			}
			else
			{
				// do something on command
				_variant_t varEmpty;
				_variant_t varURL;
				
				// ===========================================================
				// Added by daveliu - Start
				// ===========================================================
				LONG result;
				HKEY hKey;
				char sessionID[20];
				DWORD dwBufLen = sizeof(sessionID);
				DWORD dwRetVal = 0;

				// Open a registry key
				result = (dwRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
							"SOFTWARE\\CathayBK\\MyATM_SuperKey",
							0,
							KEY_QUERY_VALUE|KEY_SET_VALUE,
							&hKey));

				if(result == ERROR_SUCCESS) // If opening the registry key is successful
				{
					result = RegQueryValueEx(hKey, "SessionID", NULL, NULL, (LPBYTE)sessionID, &dwBufLen);
					
					if (result == ERROR_SUCCESS) // If getting the "SessionID" value is successful
					{
						varURL = _bstr_t(g_WWURL) + sessionID;
					}
					else
					{
						varURL = _bstr_t(g_WWURL) + "00"; // If "SessionID" value is not found, return "00" in querystring. Example: "?SessionID=00"
					}

					RegCloseKey(hKey);
				}
				else
				{
					varURL = _bstr_t(g_WWURL) + "0"; // if the registry key is not found, return "0" in querystring. Example: "?SessionID=0"
				}
				
				// ===========================================================
				// Added by daveliu - End
				// ===========================================================
				
				// varURL = _bstr_t(g_WWURL);

				m_pIE->Navigate2(&varURL, &varEmpty, &varEmpty, &varEmpty, &varEmpty);

				hr = S_OK;
			}
		}
	}

	return hr;
}

STDMETHODIMP MyBankApp::SetSite(IUnknown* punkSite)
{
 	// TODO: Add your implementation code here

	HRESULT hr; 
m_pIOSite = punkSite; 
//If punkSite is not NULL, a new site is being set. 
if(m_pIOSite) 
{ 
//Get the parent window. 
IOleWindowPtr pOleWindow; 
m_hWndParent = NULL; 
if (pOleWindow = m_pIOSite) 
pOleWindow->GetWindow(&m_hWndParent); 
if(!m_hWndParent) 
return E_FAIL; 
// Get the top level IE IWebBrowser 
IServiceProviderPtr pSP = m_pIOSite; 
if (m_pIE) 
m_pIE = NULL; 
hr = pSP->QueryService(SID_SWebBrowserApp, IID_IWebBrowser, (void**)&m_pIE); 

}

 	return S_OK;
}
STDMETHODIMP MyBankApp::GetSite(REFIID riid, LPVOID *ppvReturn)
{
 	// TODO: Add your implementation code here
	*ppvReturn = NULL;

	if(m_pIOSite)
	   return m_pIOSite->QueryInterface(riid, ppvReturn);

	return E_FAIL;

}

Open in new window

MyBankApp.cpp
My-ATM-SuperKey.reg
0
Dangeriz
Asked:
Dangeriz
3 Solutions
 
pgnatyukCommented:
GetLastError() gives the error code.
(In your code you mixed multi-byte character set and Unicode.)
Seems like your project support multi-byte character set. You open key "SOFTWARE\\CathayBK\\MyATM_SuperKey" and retrieve value of SessionID. if this value found:
varURL = _bstr_t(g_WWURL) + sessionID
So where is the mistake? The application fails to open the key or to retriev the value?
As I said you can use GetLastError() like:
DWORD nErr = GetLastError();
Or in the watch window type $ERR (if I remember correctly).
 
 
0
 
jkrCommented:
In addition, 'FormatMessage()' will help you to get a textual epresentation of what went wrong. See e.g. http://msdn.microsoft.com/en-us/library/ms680582(VS.85).aspx ("Retrieving the Last-Error Code")
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError(); 

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

    // Display the error message

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        (lstrlen((LPCTSTR)lpMsgBuf) + 255); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("Reading the Registry failed with error %d: %s"), 
        dw, lpMsgBuf); 
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); 

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);

Open in new window

0
 
js-profiCommented:
The code you posted is only reading from registry. How the entry was written? After error could you check whether the entry still exists in registry?

 
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
DangerizAuthor Commented:
pgnatyuk:
- The GetLastError() returns a 0. I'm assuming that the GetLastError() function didn't find any errors.
- Typing  $ERR in the watch window doesn't do anything (it says it can't find the symbol "$ERR").
- My application is failing on opening the registry key for the second time (see the code snippet).

jkr:
- I'm using an older version of Visual C++ R 6.0 compiler and it doesn't want to compile the strsafe.h. It says "no such file or directory". I'm using an old VPC with Windows 2000, and just installed the Windows SDK (which took 6 hours!) but it still didn't work. I don't think i can use this example. Thanks anyway.

js-profit:
- The writing to the registry is done by another component which I'm not responsible for. I was instructed to assume that the registry entry is always there and I just have to read it. When my application failed clicking on the button for the second time, the registry was checked and it still existed.

This behavior doesn't happen in my dev environment, only on my colleague's computer when we tested it. From the SessionID=0 in the URL, I can determine that the opening of the registry failed. Example: result != ERROR_SUCCESS. So I just need to know if the result is not equal to ERROR_SUCCESS then where can I fish the error message from?
// Open a registry key 
result = (dwRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\CathayBK\\MyATM_SuperKey", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hKey));
 
if(result == ERROR_SUCCESS)
{
     // Opens the key successfully the first time
     RegCloseKey(hKey); 
}
else 
{ 
     // Fails opening the key for the second time, and everytime after that.
} 

Open in new window

0
 
pgnatyukCommented:
http://msdn.microsoft.com/en-us/library/ms724897(VS.85).aspx

Return Value
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in Winerror.h. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTEM flag to get a generic description of the error.

Remarks
Unlike the RegCreateKeyEx function, the RegOpenKeyEx function does not create the specified key if the key does not exist in the registry.


I think you need to check the names you give for your keys and values. Your project uses the Multibyte Character Set. If I'm right, you will not see any Unicode name in the registry. I think this is the mistake.  This char SessionID[20] in your code looks very bad.
It is not a big deal to add 'W' for all registry functions and 'L' before all names.

0
 
DangerizAuthor Commented:
The names I gave the key and value is in English. I don't know how to set the encoding, but the application reads the registry on the first run? Surely, this isn't related to the encoding then, because how can the encoding change the second time?

I've just changed the char SessionID[20] to SessionID[50], hope that makes it looks better :p
0
 
DangerizAuthor Commented:
I'm also trying to get the descriptive error message by using the FormatMessage function:
http://msdn.microsoft.com/en-us/library/ms680582(VS.85).aspx

...but my compiler can't open the strsafe.h include file - It says "No such file or directory".
0
 
pgnatyukCommented:
just use WCHAR SessionID[64]

Seems like you add 0 to the strings you are writing to the registry. Because everything in the registry is Unicode, you can add such name (with 0), but when you read such name, you cannot see it - 0 means end of the string. In this case you will always see ERROR_SUCCESS.

So I've told you, switch to the Unicode functions: they all have W in the end and their parameters are WCHAR (wchar_t) instead of char. That's all.
0
 
DangerizAuthor Commented:
I've found out that the problem was with Windows Vista and 7's UAC denying read access to the registry. The workaround is to launch IE (since it's a custom button on IE) with "run as admin", or to save the registry key under HKCU (doesn't need admin to read from here). Why it worked the first time on another machine without running as admin is still a mystery. Since this is confirmed to be the problem, obtaining the error message is not necessary anymore (i'm guessing that the message would be "access denied").

I'm assigning points to those who have helped me with more information about my original problem - how to get more information from the error message.

I'll open another question for the UAC problem.

Thanks you all for your help.
0

Featured Post

New feature and membership benefit!

New feature! Upgrade and increase expert visibility of your issues with Priority Questions.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now