Weird if behavior, what is the magic behind gcnew(or may be something else)?

I have managed to make this piece of code work, I just want to know what was happening behind the scene. Such problems always make me freak out...

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
//headers and defines
#include<windows.h>
#include<string>
System::Windows::Forms::OpenFileDialog^ openOri;
//end of define

//On_Load_Event
this->openOri = (gcnew System::Windows::Forms::OpenFileDialog());
HKEY hkey;
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\foo\\"), 0, KEY_READ, &hkey) == ERROR_SUCCESS){
  PPERF_DATA_BLOCK querydata = (PPERF_DATA_BLOCK)malloc(999);
  DWORD cbData;
  if (RegQueryValueEx(hkey, TEXT("INSTALLDIR"), NULL, NULL, (LPBYTE)querydata, &cbData) == ERROR_SUCCESS){
    wstring insdir(cbData / sizeof(wchar_t), L'\0');
    if (RegQueryValueEx(hkey, TEXT("INSTALLDIR"), NULL, NULL, reinterpret_cast<LPBYTE>(&insdir[0]), &cbData) == ERROR_SUCCESS){
      size_t firstNull = insdir.find_first_of(L'\0');
      if (firstNull != string::npos)
        insdir.resize(firstNull);
    }
    System::String^ tempstr=gcnew String(insdir.c_str());
    openOri->InitialDirectory = tempstr;
    textbox->Text = tempstr;
    //textbox->Text = gcnew String(insdir.c_str());
  }
  else
    textbox->Text = L"Open subkey failed";
}
else{	     
  textbox->Text = L"Open key failed";
}
RegCloseKey(hkey);
//end of code 


Basically this piece of code is triggered with load event i.e. runs automatically on program start up. Then it retrieves the installation path of a particular software from registry and sets the open file dialog initial directory to it.

The problem is, as you can see I commented textbox->Text = gcnew String(insdir.c_str());, then the textbox would show "Open subkey failed". If I comment textbox->Text = tempstr; instead, the textbox will show the right directory path and open file dialog also works fine. If I comment both of them, it does not work. If I uncomment both of them, it works. If I uncomment both of them and change their order, it works.

I then did some further testing, since I do not need the querydata in Line 13 so I changed it to NULL and commented Line 11. Then somehow it worked(with Line 23 commented)! I really cannot understand what happened...
I'm bit conflicted on whether or not to post this because I suspect that Cli has a more direct mechanism for the same basic idea of what I am showing you. But regardless of what implementation you choose, STOP SCREWING AROUND IN THE REGISTRY. This is for your own good, this is an ad-hoc solution and it is a terrible habit to get into.

Remember this is in C:
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
IWbemLocator* pLocation  = NULL;
IWbemServices* pService = NULL;

ULONG ReturnValue = 0;

const int NumOfItems = 100; //Feel Free To Change This Value. I Grabbed This Code From A Project Where It Was Necessary.

IEnumWbemClassObject* pEnumClassObj = NULL;
IWbemClassObject*     pClassCol[NumOfItems];

CoInitializeEx(NULL, COINIT_MULTITHREADED);
CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*) &pLocation);
pLocation->ConnectServer(BSTR(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pService);
CoSetProxyBlanket(pService, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);


VARIANT varLocation;
    V_VT(&varLocation) = VT_BSTR;

BSTR WMIQuery = SysAllocString(L"Select * From WIN32_PRODUCT Where Name Like YOUR_TARGET_APPLICATION_NAME");

pService->ExecQuery(BSTR(L"WQL"), WMIQuery, WBEM_FLAG_BIDIRECTIONAL, NULL, &pEnumClassObj);

pEnumClassObj->Next(WBEM_INFINITE, 1 pClassCol, &ReturnValue); //This Snipit Assumes That There Is Only One Instance Of The Application. Otherwise Put This Part In A Loop

pClassCol[0]->Get(BSTR(L"InstallLocation"), 0, &varLocation, NULL, 0); //See Previous Comment

std::wcout << L"Install Location: " << varLocation.bstrVal << L"\n";

pClassCol[0]->Release();

VariantClear(varLocation);


This was adapted from working code, I may have broken something while I was clarifying variable names and adapting it to your need but if I did I will be able to fix it. You will have to link to AdvApi32.lib, WbemUuid.Lib, Ole32.Lib and OleAut32.Lib and include WTypes.h, OleAuto.h, Aclapi.h, Objbase.h and I believe AccCtrl.h (but off the top of my head I can't remember if that is for a component that is relevant to this block of code or if it was from another part of that project). I wrote this to show you how powerful COM+ is and to encourage you to learn it. Sorry for the derail, thanks for letting me rant a bit.

EDIT: In the part where I have YOUR_TARGET_APPLICATION_NAME, this should be the name of the application enclosed in percent signs, like this %APPLICATION_NAME% this part of the WQL syntax.

EDIT_2: I should mention that this particular query takes some time to return. Give it about 5 mins. It's not because it's COM, it's due to this particular WMI class. Every other one is as quick as you can expect an application written in C to be.
Last edited on
After rethinking this piece of code...

Why did I have to call RegQueryValueEx() twice?

1
2
3
4
5
6
7
PVOID pvData[512];
DWORD pcbData = 512;
if (RegGetValue(HKEY_CURRENT_USER, TEXT("Software\\foo"), TEXT("INSTALLDIR"), RRF_RT_REG_SZ, NULL, &pvData, &pcbData) == ERROR_SUCCESS){
  System::String^ tempstr = gcnew String((wchar_t*)pvData);
  openOri->InitialDirectory = tempstr;
  textbox->Text = tempstr;
}


Now I need only one call instead of three. This lacks protection against buffer overflow, but in my case this is not likely to happen so I just leave it there.

The reason why that if in OP behaves soooooooooooo strange remains unseen though.
Topic archived. No new replies allowed.