Solved

Writing/Reading a structure in registry

Posted on 2014-04-24
15
480 Views
Last Modified: 2014-05-03
Hello experts

Please help how to write and read a simple structure , structure contains one date field and one integer.

I need this structure data to access from other process.

Thanks in advance
0
Comment
Question by:HarishMinu
  • 5
  • 4
  • 3
  • +2
15 Comments
 
LVL 86

Assisted Solution

by:jkr
jkr earned 250 total points
ID: 40020651
You have two options - writing each individual field as a separate value or using REG_BINARY to write the entire struct, e.g.

bool WriteMyStruct(HKEY Key, MyStruct* pBuf) 
{
    if (RegSetValueEx (Key, _T("MyStruct"), 0, REG_BINARY, (LPBYTE) pBuf,  
                      sizeof(MyStruct)) == ERROR_SUCCESS) return true; 
    else return false; 
}

Open in new window


To read that, you'd just use

bool ReadMyStruct(HKEY Key, MyStruct* pBuf) 
{
    DWORD dwType = REG_BINARY;
    DWORD dwSize = sizeof(MyStruct);
    if (RegQueryValueEx (Key, _T("MyStruct"), 0, &dwType, (LPBYTE) pBuf,  
                      &dwSize) == ERROR_SUCCESS) return true; 
    else return false; 
}

Open in new window

0
 
LVL 8

Expert Comment

by:Subrat (C++ windows/Linux)
ID: 40020668
Your requirement is not fully clear. But I hope you are new to C++ struct. If so please follow the link:
http://www.cplusplus.com/doc/tutorial/structures/

PSceoudo code:
struct myStruct {
  std:;string data1;
  int data2;
};

Regarding Registry:
You can use
RegOpenKeyEx()
RegQueryValueEx()
RegCloseKey()
This will read the value from registry according to the input to the functions.
Finally set read out values to structure.

If you want to access data of one process in other process then you have to use Inter Process Communication(IPC) or Shared Memory.

If you are facing any specific issue in codeing then you can show the snap shot!
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 40020786
Since those are just two values you need to manage, use the "write individual field" approach. Storing binary data should be done only for more complex scenarios.
0
 

Author Comment

by:HarishMinu
ID: 40021895
My requirement is

One process will be invoked many times by external process to create multiple tasks.
First it will check No.1 task if it is free it will assign the job to process else it will create No.2 task and goes on for N tasks.

In order to synchronize, I need to keep the data of the process ( time created and process id, etc. ) in a temporary memory and reset the data after completion. If 2nd process is invoked it will check No1 task data, it is already in processing it will go and create No2 task else it will assign to No1 task.

what will be best way to implement this ?
please let me know if it is not clear.

Apologies for not explaining in detail.
0
 
LVL 32

Expert Comment

by:sarabande
ID: 40022186
if the tasks are threads and not processes, they could access any shared data of the (parent) process. so writing to registry or any other shared storage would not be necessary.

struct threadinfo 
{  
    HANDLE threadhandle; 
    bool busy;
    threadinfo() :  threadhandle(NULL), busy(false) {}
};

class ThreadManager
{
    enum { max_threads = 64 };
    std::string date;
    int number;
    threadinfo ti[max_threads];

    void handleThreads(const std:.string& dat, int num);
    bool wait_for_task();

    static void thread_func(void * p);
public: 
    const std::string & get_date() { return date; }
    int  get_num() { return number; }
};

void ThreadManager::handleThreads(const std:.string& dat, int num)
{
    date = dat;
    number = num;

    while (true)
    {
         if (wait_for_task() == false) break;
         
         for (int n = 0; n <  max_threads; ++n)
         {
              if (ti[n].busy == false)
              {
                    ti[n].busy = true;
                    ti[n].thread_handle = _begin_thread(thread_func, 0, this);
                    break;
             } 
        }
} 

Open in new window


with the above all threads could access the date and number by means of the ThreadManager.

void ThreadManager::thread_func(void * p)
{
    ThreadManager * pthis = (ThreadManager *)p;
    ...
    std::string date = pthis->get_date();
    ...

Open in new window


if the tasks are different processes i nevertheless would use a similar concept. you either pass the information when the processes were created - for example by commandline arguments- or if the client processes can be used for different tasks - you do some program-to-program communication (see also comment of Subrat), where windows messages probably are the easiest way though they require at least a pseudo window and message loop for each participant.

Sara
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 40022253
Maybe using a Shared Memory segment is a better idea for interprocess communication ...
0
 
LVL 86

Expert Comment

by:jkr
ID: 40022282
One good start certainly would be to post the exact declaration of your structure.
0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 32

Accepted Solution

by:
sarabande earned 250 total points
ID: 40022294
yes, QLemo is right. shared memory is a good idea for p2p. if the processes are window-less shared memory is a fine and quick solution:

   
HANDLE hMapFile = NULL;
   MyStruct * pBuf = NULL; // pointer to structure with date and number

   hMapFile = CreateFileMapping(
                 INVALID_HANDLE_VALUE,    // use paging file
                 NULL,                    // default security
                 PAGE_READWRITE,          // read/write access
                 0,                       // maximum object size (high-order DWORD)
                 sizeof(MyStruct),                // maximum object size (low-order DWORD)
                 "SomeUniqueName");                 // name of mapping object

   if (hMapFile == NULL)
   {
      log_error("Could not create file mapping object. Error=", GetLastError());
      return 1;
   }

   pBuf = (MyStruct*) MapViewOfFile(hMapFile,   // handle to map object
                        FILE_MAP_ALL_ACCESS, // read/write permission
                        0,
                        0,
                        BUF_SIZE);

   if (pBuf == NULL)
   {
      log_error("Could not map view of file. Error=", GetLastError());
      CloseHandle(hMapFile);
      return 1;
   }

Open in new window


you can use the same code for write and read. in case of reading you might check after CreateFileMapping successfully returning a handle that GetLastError() returns ERROR_ALREADY_EXISTS cause the reading process should be second after the writing process.

alternatively the client processes may use OpenFileMapping as described in

http://msdn.microsoft.com/en-us/library/windows/desktop/aa366551(v=vs.85).aspx

Sara
0
 

Author Comment

by:HarishMinu
ID: 40027584
Thanks Sara

CopyMemory method is missing in above code, Is it is not necessary ?

I am unable to set the first PVOID parameter to struct in CopyMemory method.

Thank you .
0
 
LVL 86

Expert Comment

by:jkr
ID: 40027675
That basically works the same way as I showed you how to do that with the registry, which was your original question. Why do you want to abandon your own approach now?
0
 
LVL 32

Expert Comment

by:sarabande
ID: 40027832
CopyMemory method is missing in above code, Is it is not necessary

it depends. if you return the pbuf pointer as const and the caller would assign it to its own struct variable it is safe enough:

mystruct * ps = get_mystruct_from_shared_memory();

if (ps == NULL)
    return;

mystruct ms;
ms = *ps;   // copies the shared memory to a local

Open in new window


registry entries rarely are used for p2p (too slow). it is recommendable for properties or settings, though. so shared memory is fine for client-server on one machine. you could have a big structure which has a separate section for each participant. that way each side could write to its exclusive space in memory. you only would need to lock read and write operations by a named mutex if the information was updated periodically. if the data is more a constant which is not a matter of change the registry approach jkr has shown is more simple and allows you an easy external update by using regedit.

Sara
0
 

Author Comment

by:HarishMinu
ID: 40027928
here is my entire code
main

#include "stdafx.h"

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>

struct MyStruct
{
      int ID;
      LPWSTR text;
};

#define BUF_SIZE 256


int _tmain(int argc, _TCHAR* argv[])
{



      HANDLE hMapFile = NULL;
    MyStruct * pBuf = new MyStruct; // pointer to structure with date and number
      pBuf->ID = GetCurrentProcessId ();
      pBuf->text = L"Test1";

   hMapFile = CreateFileMapping(
                 INVALID_HANDLE_VALUE,    // use paging file
                 NULL,                    // default security
                 PAGE_READWRITE,          // read/write access
                 0,                       // maximum object size (high-order DWORD)
                 sizeof(MyStruct),                // maximum object size (low-order DWORD)
                 L"SomeUniqueName");                 // name of mapping object

   if (hMapFile == NULL)
   {
      _tprintf(TEXT("Could not create file mapping object (%d).\n"),
             GetLastError());      return 1;
   }

   pBuf = (MyStruct*) MapViewOfFile(hMapFile,   // handle to map object
                        FILE_MAP_ALL_ACCESS, // read/write permission
                        0,
                        0,
                        BUF_SIZE);

   if (pBuf == NULL)
   {
    _tprintf(TEXT("Could not create file mapping object (%d).\n"),
             GetLastError());
      CloseHandle(hMapFile);
      return 1;
   }


   UnmapViewOfFile(pBuf);

   CloseHandle(hMapFile);
 

      return 0;
}




Client

// ShareMem.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>

struct MyStruct
{
      int ID;
      LPWSTR text;
};

#define BUF_SIZE 256


int _tmain(int argc, _TCHAR* argv[])
{

      HANDLE hMapFile = NULL;
      MyStruct * pBuf = new MyStruct; // pointer to structure with date and number
      pBuf->ID = GetCurrentProcessId ();
      pBuf->text = L"Test1";

      hMapFile = CreateFileMapping(
            INVALID_HANDLE_VALUE,    // use paging file
            NULL,                    // default security
            PAGE_READWRITE,          // read/write access
            0,                       // maximum object size (high-order DWORD)
            sizeof(MyStruct),                // maximum object size (low-order DWORD)
            L"SomeUniqueName");                 // name of mapping object

      if (hMapFile == NULL)
      {
            _tprintf(TEXT("Could not create file mapping object (%d).\n"),
                  GetLastError());      return 1;
      }

      DWORD error = GetLastError ();

      if(error == ERROR_ALREADY_EXISTS)
      {


            pBuf = (MyStruct*) MapViewOfFile(hMapFile,   // handle to map object
                  FILE_MAP_ALL_ACCESS, // read/write permission
                  0,
                  0,
                  BUF_SIZE);

            if (pBuf == NULL)
            {
                  _tprintf(TEXT("Could not create file mapping object (%d).\n"),
                        GetLastError());
                  CloseHandle(hMapFile);
                  return 1;
            }

            printf("ID - %d, Name - %ls", pBuf->ID , pBuf->text );

      }

      UnmapViewOfFile(pBuf);

   CloseHandle(hMapFile);
 
      return 0;
}

I cannot able to get the struct data in the client. pls help
0
 
LVL 86

Expert Comment

by:jkr
ID: 40027983
For either approach, you need to use

struct MyStruct
{
      int ID;
      wchar_t text[BUF_SIZE];
};

Open in new window

since a LPWSTR is a pointer and does not make sense in another process' context.


I can''t help, but

#include "stdafx.h"

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <string.h>



#define BUF_SIZE 256

struct MyStruct
{
      int ID;
      wchar_t text[BUF_SIZE9;
};

bool WriteMyStruct(MyStruct* pBuf) 
{
    HKEY hKey;
    bool bResult = false;

    RegOpenKeyEx(HKEY_CURRENT_USER,L"MyApp",0, KEY_WRITE, '&hKey);

    if (RegSetValueEx (Key, _T("MyStruct"), 0, REG_BINARY, (LPBYTE) pBuf,  
                      sizeof(MyStruct)) == ERROR_SUCCESS) bResult = true; 
    
    RegCloseKey(hKey);

    return bResult;
}
                                            


int _tmain(int argc, _TCHAR* argv[])
{

      MyStruct * pBuf = new MyStruct; // pointer to structure with date and number
      pBuf->ID = GetCurrentProcessId ();
      wcscpy(pBuf->tex,L"Test1");

      WriteMyStruct(pBuf);

      return 0;
}

Open in new window


and

#include "stdafx.h"

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <string.h>



#define BUF_SIZE 256

struct MyStruct
{
      int ID;
      wchar_t text[BUF_SIZE9;
};


bool ReadMyStruct(MyStruct* pBuf) 
{
    DWORD dwType = REG_BINARY;
    DWORD dwSize = sizeof(MyStruct);
    HKEY hKey;
    bool bResult = false;

    RegOpenKeyEx(HKEY_CURRENT_USER,L"MyApp",0, KEY_WRITE, '&hKey);


    if (RegQueryValueEx (Key, _T("MyStruct"), 0, &dwType, (LPBYTE) pBuf,  
                      &dwSize) == ERROR_SUCCESS) bResult = true; 


    RegCloseKey(hKey);

    return bResult;
}
                                            
                                            


int _tmain(int argc, _TCHAR* argv[])
{

      MyStruct * pBuf = new MyStruct; // pointer to structure with date and number

      ReadMyStruct(pBuf);

      return 0;
}

Open in new window


looks a little less complicated. Plus it is/was your very own approach.
0
 
LVL 86

Expert Comment

by:jkr
ID: 40027998
One caveat - make sure that "HKEY_CURRENT_USER\MyApp" does actually exist.
0
 
LVL 32

Expert Comment

by:sarabande
ID: 40028892
I cannot able to get the struct data in the client. pls help

in both programs you need to add a wait such that the "server" and "client" both can keep up holding a handle on the shared memory. when there is no program which has an open handle to the shared memory, windows will free the space.

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <string.h>
you should turn both the projects from 'using precompiled headers' to 'not using precompiled headers' both for debug and release configuration. for that you would remove stdafx.cpp from project tree (you can only remove or delete it that makes no difference) and then go to configuration properties - c/c++- precompiled headers and change the 'precompiled header' option. precompiled headers is a compiler speed optimization which don't make so much sense for non-mfc projects and even for those it could make more problems as it helps. also I would recommend to change the character set from UNICODE to 'Multibyte' in the configuration properties - general (again both for debug and release). if you do so you could forget all the TCHAR/wchar_t, _T/L"", LPCTSTR, LPTSTR, _tmain, -tprintf stuff and use char, "", const char*, char *, main and std::cout instead:

#include <windows.h>
#include <string>
#include <iostream>

struct MyStruct
{
      int    i;
      char text[64];  // don't pass pointers but characters (see comment of jkr)
};
 
int main(int narg, char * szargs[])
{
       MyStruct ms = { 0, "Hello Client" };  // init structure or use strcpy(ms.text, "some text");
       // put here your code for writing to shared memory
       // you also can do the UnmapViewOfFile 
       // but don't close the handle to the memory mapped file
       ...
       std::cout << "server: successfully written a message to client into shared memory" << std::endl;
       std::cout << "server: waiting for client to read from shared memory: ";
       int r;
       std::cin >> r;         // here the program waits until you enter a number.
       
       // after input from console you can free the shared memory from your side
       CloseHandle(hMapFile);
       return r;
}

Open in new window


the client would be made similar. you would start the server first and then the client. both programs would print the success message on the screen and wait for input. you can stop the scenario by inputting a number to either program.

Sara
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Suggested Solutions

Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
This is about my first experience with programming Arduino.
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now