# Hex-Rays v1.6 vs. v1.5 Decompiler Comparison Page

## Hex-Rays v1.6 vs. v1.5 Decompiler Comparison Page

Below you will find side-by-side comparisons of v1.5 and v1.6 decompilations. Please maximize the window too see both columns simultaneously.

The following examples are displayed on this page:

1. [Inline CFString constants](#inline-cfstring-constants)
2. [More humanly if-conditions](#more-humanly-if-conditions)
3. [Support for CONTAINING\_RECORD macro](#support-for-containing_record-macro)
4. [Support for LIST\_ENTRY macros](#support-for-list_entry-macros)
5. [Better tail call recognition](#better-tail-call-recognition)
6. [Improved memset recognition](#improved-memset-recognition)
7. [Support for TEB/KPCR references](#support-for-tebkpcr-references)
8. [Better char/short variable recognition](#better-charshort-variable-recognition)
9. [Better recognition of inline functions](#better-recognition-of-inline-functions)
10. [Structure copying - 1](#structure-copying---1)
11. [Structure copying - 2](#structure-copying---2)
12. [Structure copying - 3](#structure-copying-3)
13. [Support for union fields](#support-for-union-fields)
14. [Support for merged calls](#support-for-merged-calls)

NOTE: these are just some selected examples that can be illustrated as a side-by-side difference. Hex-Rays Decompiler v1.6 includes are many other improvements and new features that are not mentioned on this page - simply because there was nothing to compare them with. Also, some improvements have already been illustrated in the previous comparisons. Please refer to the [news page](https://hex-rays.com/products/decompiler/news/) for more details.

***

### Inline CFString constants

This simple improvement can substantially speed up analysis of Objective C code: CFString text constants are immediately visible in the output.

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
void *__cdecl _PMProxy_showHistroyWindow__()
{
  void *v0; // eax@1

  v0 = objc_msgSend("NSWorkspace", "sharedWorkspace");
  return objc_msgSend(v0, "openFile:withApplication:", CFSTR("/var/log/cups/error_log"), CFSTR("Console"));
}
```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python
void *__cdecl _PMProxy_showHistroyWindow__()
{
  void *v0; // eax@1

  v0 = objc_msgSend("NSWorkspace", "sharedWorkspace");
  return objc_msgSend(v0, "openFile:withApplication:", &cfstr_VarLogCupsErro, &cfstr_Console);
}
```

{% endtab %}
{% endtabs %}

### More humanly if-conditions

The decompiler generates much more readable text by dividing complex conditions into smaller chunks. The output is longer but hey, sometimes it makes sense to be verbose! :)

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
  pos1 = *mark1;
  err.x = parseMark(_viewer, &_text, mark1, _pInfo, &_iLineNo, &point1);
  if ( err.x )
    return err.x;
  if ( mark2 )
  {
    pos2 = *mark2;
    err.x = parseMark(_viewer, &pageNo2, mark2, _pInfo, &lineNo2, &err);
    if ( err.x )
      return err.x;
  }
  if ( pRects )
  {
    curPage = _viewer->nPage;
    if ( pageNo2 < curPage || _text > curPage )
      return err.x;
  }
```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python
  pos1 = *mark1;
  err.x = parseMark(_viewer, &_text, mark1, _pInfo, &_iLineNo, &point1);
  if ( err.x
    || mark2 && (pos2 = *mark2, (err.x = parseMark(_viewer, &pageNo2, mark2, _pInfo, &lineNo2, &err)) != 0)
    || pRects && ((curPage = _viewer->nPage, pageNo2 < curPage) || _text > curPage) )
    return err.x;
```

{% endtab %}
{% endtabs %}

### Support for CONTAINING\_RECORD macro

iv class="cmptell"> The decompiler knows how to use the [CONTAINING\_RECORD](http://msdn.microsoft.com/en-us/library/windows/hardware/ff542043\(v=vs.85\).aspx) macro it the output to get rid of typecasts. As soon as the variable types are correctly set, it replaces casts with a simple macro call.

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
  _HW_STREAM_OBJECT *HwStreamObject; 
  _STREAM_OBJECT *StreamObject; // esi@1
  StreamObject = CONTAINING_RECORD(HwStreamObject, _STREAM_OBJECT, HwStreamObject);
```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python
  _HW_STREAM_OBJECT *HwStreamObject; 
  _STREAM_OBJECT *StreamObject; // esi@1
  StreamObject = (_STREAM_OBJECT *)((char *)&HwStreamObject[-2] - 36);
```

{% endtab %}
{% endtabs %}

### Support for LIST\_ENTRY macros

We added recognition of [LIST\_ENTRY](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554296\(v=vs.85\).aspx) macros. While not all cases are handled yet, it usually works quite well. Saves you from the mental effort of recognizing these macros yourself.

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
void __stdcall SCStartRequestOnStream(_STREAM_OBJECT *a1, _DEVICE_EXTENSION *a2)
{
  KSPIN_LOCK *v2; // ebx@1                                                            

  v2 = &a2->SpinLock;
  KefAcquireSpinLockAtDpcLevel(&a2->SpinLock);
  if ( a1->ReadyForNextDataReq && !IsListEmpty(&a1->DataPendingQueue) )
  {
    SCDequeueAndStartStreamDataRequest(a1);
    KefAcquireSpinLockAtDpcLevel(v2);
  }
  if ( !a1->ReadyForNextControlReq || IsListEmpty(&a1->ControlPendingQueue) )
    KefReleaseSpinLockFromDpcLevel(v2);
  else
    SCDequeueAndStartStreamControlRequest(a1);
}
```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python
int __stdcall SCStartRequestOnStream(_STREAM_OBJECT *a1, _DEVICE_EXTENSION *a2)
{
  char *v2; // ebx@1
  int result; // eax@6

  v2 = (char *)&a2->SpinLock;
  KefAcquireSpinLockAtDpcLevel(&a2->SpinLock);
  if ( a1->ReadyForNextDataReq && a1->DataPendingQueue.Flink != &a1->DataPendingQueue )
  {
    SCDequeueAndStartStreamDataRequest(a1);
    KefAcquireSpinLockAtDpcLevel(v2);
  }
  if ( a1->ReadyForNextControlReq && a1->ControlPendingQueue.Flink != &a1->ControlPendingQueue )
    result = SCDequeueAndStartStreamControlRequest(a1);
  else
    result = KefReleaseSpinLockFromDpcLevel(v2);
  return result;
}
```

{% endtab %}
{% endtabs %}

### Better tail call recognition

A much better recognition of tail call optimization leads to less JUMPOUT() calls in the output. The call arguments are recognized correctly. The function return value is not lost anymore.

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
BOOL __stdcall BaseDllInitialize(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
  if ( fdwReason == 1 )
    __security_init_cookie();
  return _BaseDllInitialize(hinstDLL, fdwReason, lpReserved);
}
```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python
BOOL __stdcall BaseDllInitialize(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
  if ( fdwReason == 1 )
    __security_init_cookie();
  JUMPOUT(*(int *)_BaseDllInitialize);
}
```

{% endtab %}
{% endtabs %}

### Improved memset recognition

Six non-trivial lines of code have been collapsed into one simple line. We are happy with this improvement!

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
  memset(v10, 0, v10->cbSize);
```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python
      v15 = v10->cbSize;
      v16 = v10->cbSize >> 2;
      memset(v10, 0, 4 * v16);
      v17 = (int)((char *)v10 + 4 * v16);
      for ( i = v15 & 3; i; --i )
        *(_BYTE *)v17++ = 0;
```

{% endtab %}
{% endtabs %}

### Support for TEB/KPCR references

No more cryptic offsets anymore. As an additional bonus, the decompiler automatically determines variable types because it can use the [TEB layout](http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Thread/TEB.html). By the way, KPCR fields are recognized too, you just need to load the corresponding til file!

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
SessionId = NtCurrentTeb()->ProcessEnvironmentBlock->SessionId;
```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python
SessionId = *(_DWORD *)(*(_DWORD *)(__readfsdword(24) + 48) + 468);
```

{% endtab %}
{% endtabs %}

### Better char/short variable recognition

The previous version of the decompiler failed to create a 16-bit variable that was stored by the compiler in `bx`. This had some very nasty consequences: the function prototype had an incorrect input argument (ebx) and the calling convention was wrong. While it was possible to correct it by specifying the function prototype manually, the new version lifts this burden from you.

The new version takes care of this situation much better. It uses a more fine-grained approach to variable allocation. It created a small 16-bit variable `v4`. No more ugly LOWORD() macro, the output is cleaner. The correctly determined function prototype will help when decompiling other functions as well because there will be less parasitic arguments and less confusion.

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
signed int __thiscall sub_600112F7(void *this, int a2, int a3)
{
  unsigned __int16 v4; // bx@1
  v10 = this;
  v4 = *(_WORD *)(a2 + 12);
```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python
signed int __userpurge sub_600112F7<eax>(int a1<ecx>, int a2<ebx>, int a3, int a4)
{
  v10 = a1;
  LOWORD(a2) = *(_WORD *)(a3 + 12);
```

{% endtab %}
{% endtabs %}

### Better recognition of inline functions

Sorry for a long sample, the previous version of the decompiler was not handling strlen() well enough. It is a never ending fight and perfection is impossible, but we still continue to work on it. Recognition of inline functions is an incredibly hard problem, but the new version has a better engine to recognize them. There is plenty of room for improvement, to put it mildly.

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
  v18 = (char *)operator new(v15);
  strcpy(v18, *v3);
  strcat(v18, " ");
  strcat(v18, v3[1]);
  strcat(v18, " ");
  strcat(v18, v3[2]);
  if ( v3[3] )
  {
    argca = v3 + 3;
    v25 = v3 + 3;
    do
    {
      strcat(v18, " \"");
      strcat(v18, *argca);
      if ( (*argca)[strlen(*argca) - 1] == 92 )
        strcat(v18, "\\");
      strcat(v18, "\"");
      ++v25;
      argca = v25;
    }
    while ( *v25 );
  }
```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python
  v27 = (char *)operator new(v24);
  v28 = v27;
  strcpy(v27, *v3);
  v29 = -1;
  v30 = " ";
  do
  {
    if ( !v29 )
      break;
    v12 = *v30++ == 0;
    --v29;
  }
  while ( !v12 );
  v31 = ~v29;
  v32 = v31;
  v33 = &v30[-v31];
  v34 = -1;
  v35 = v27;
  do
  {
    if ( !v34 )
      break;
    v12 = *v35++ == 0;
    --v34;
  }
  while ( !v12 );
  memcpy(v35 - 1, v33, v32);
  v36 = v3[1];
  v37 = -1;
  do
  {
    if ( !v37 )
      break;
    v12 = *v36++ == 0;
    --v37;
  }
  while ( !v12 );
  v38 = ~v37;
  v39 = &v36[-v38];
  v40 = v38;
  v41 = v27;
  v42 = -1;
  do
  {
    if ( !v42 )
      break;
    v12 = *v41++ == 0;
    --v42;
  }
  while ( !v12 );
  memcpy(v41 - 1, v39, v40);
  v43 = " ";
  v44 = -1;
  do
  {
    if ( !v44 )
      break;
    v12 = *v43++ == 0;
    --v44;
  }
  while ( !v12 );
  v45 = ~v44;
  v46 = &v43[-v45];
  v47 = v45;
  v48 = v27;
  v49 = -1;
  do
  {
    if ( !v49 )
      break;
    v12 = *v48++ == 0;
    --v49;
  }
  while ( !v12 );
  memcpy(v48 - 1, v46, v47);
  v50 = v3[2];
  v51 = -1;
  do
  {
    if ( !v51 )
      break;
    v12 = *v50++ == 0;
    --v51;
  }
  while ( !v12 );
  v52 = ~v51;
  v53 = &v50[-v52];
  v54 = v52;
  v55 = v27;
  v56 = -1;
  do
  {
    if ( !v56 )
      break;
    v12 = *v55++ == 0;
    --v56;
  }
  while ( !v12 );
  memcpy(v55 - 1, v53, v54);
  if ( v3[3] )
  {
    argca = v3 + 3;
    v91 = v3 + 3;
    do
    {
      v57 = " \"";
      v58 = -1;
      do
      {
        if ( !v58 )
          break;
        v12 = *v57++ == 0;
        --v58;
      }
      while ( !v12 );
      v59 = ~v58;
      v60 = &v57[-v59];
      v61 = v59;
      v62 = v27;
      v63 = -1;
      do
      {
        if ( !v63 )
          break;
        v12 = *v62++ == 0;
        --v63;
      }
      while ( !v12 );
      memcpy(v62 - 1, v60, v61);
      v64 = *argca;
      v65 = -1;
      do
      {
        if ( !v65 )
          break;
        v12 = *v64++ == 0;
        --v65;
      }
      while ( !v12 );
      v66 = ~v65;
      v67 = &v64[-v66];
      v68 = v66;
      v69 = v27;
      v70 = -1;
      do
      {
        if ( !v70 )
          break;
        v12 = *v69++ == 0;
        --v70;
      }
      while ( !v12 );
      memcpy(v69 - 1, v67, v68);
      if ( (*argca)[strlen(*argca) - 1] == 92 )
      {
        v71 = "\\";
        v72 = -1;
        do
        {
          if ( !v72 )
            break;
          v12 = *v71++ == 0;
          --v72;
        }
        while ( !v12 );
        v73 = ~v72;
        v74 = &v71[-v73];
        v75 = v73;
        v76 = v27;
        v77 = -1;
        do
        {
          if ( !v77 )
            break;
          v12 = *v76++ == 0;
          --v77;
        }
        while ( !v12 );
        memcpy(v76 - 1, v74, v75);
      }
      v78 = "\"";
      v79 = -1;
      do
      {
        if ( !v79 )
          break;
        v12 = *v78++ == 0;
        --v79;
      }
      while ( !v12 );
      v80 = ~v79;
      v81 = &v78[-v80];
      v82 = v80;
      v83 = v27;
      v84 = -1;
      do
      {
        if ( !v84 )
          break;
        v12 = *v83++ == 0;
        --v84;
      }
      while ( !v12 );
      memcpy(v83 - 1, v81, v82);
      ++v91;
      argca = v91;
    }
    while ( *v91 );
  }
```

{% endtab %}
{% endtabs %}

### Structure copying - 1

While it is not pure C, we feel that using C++ style structure copying operations in the output adds to clarity. The above sample is almost perfect, this only possible improvement is to [map](https://docs.hex-rays.com/9.0/user-guide/decompiler/interactive/cmd_map_lvar) `_this` to `this`. The new decompiler can do that, read our [blog post](http://www.hexblog.com/?p=544) for more info.

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
void __thiscall FileInfo::InitTime(FileInfo *this)
{
  FileInfo *_this; // ST08_4@1
  _SYSTEMTIME st; // [sp+4h] [bp-18h]@1
  _FILETIME ft; // [sp+14h] [bp-8h]@1

  _this = this;
  GetSystemTime(&st);
  SystemTimeToFileTime(&st, &ft);
  _this->m_CreateTime = ft;
  _this->m_AccessTime = ft;
  _this->m_WriteTime = ft;
}
```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python

void __thiscall FileInfo::InitTime(FileInfo *this)
{
  FileInfo *_this; // ST08_4@1                                                        
  _SYSTEMTIME st; // [sp+4h] [bp-18h]@1                                               
  _FILETIME ft; // [sp+14h] [bp-8h]@1                                                 

  _this = this;
  GetSystemTime(&st);
  SystemTimeToFileTime(&st, &ft);
  _this->m_CreateTime.dwLowDateTime = ft.dwLowDateTime;
  _this->m_CreateTime.dwHighDateTime = ft.dwHighDateTime;
  _this->m_AccessTime.dwLowDateTime = ft.dwLowDateTime;
  _this->m_AccessTime.dwHighDateTime = ft.dwHighDateTime;
  _this->m_WriteTime.dwLowDateTime = ft.dwLowDateTime;
  _this->m_WriteTime.dwHighDateTime = ft.dwHighDateTime;
}
```

{% endtab %}
{% endtabs %}

### Structure copying - 2

Please note that after collapsing several assignments into one we also got rid of the intermediary `v30` variable. Very good!

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
(*pRects)[roff / 0x10u] = r;
```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python
        v30 = &(*pRects)[roff / 0x10u];
        v30->x = r.x;
        v30->y = r.y;
        v30->width = r.width;
        v30->height = r.height;                                        
```

{% endtab %}
{% endtabs %}

Sometimes compilers copy structures by DWORD's, regardless of member types. The previous version of the decompiler diligently represented these assignments in the best form it could. However, using a structure copy operation is much better, it is concise and precise.

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
  _hostobj = &machine->curHostObject;
  *_hostobj = machine->pCallObject->this;
```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python
  _this = &machine->pCallObject->this;
  _hostobj = &machine->curHostObject;
  machine->curHostObject.pNext = _this->pNext;
  *(_DWORD *)&_hostobj->nSymID = *(_DWORD *)&_this->nSymID;
  _hostobj->data = _this->data;
  _hostobj->data2 = _this->data2;
```

{% endtab %}
{% endtabs %}

### Support for union fields

Finally the decompiler has proper support for union fields. Previously analysing code with unions could quickly turn into a nightmare because the decompiler would just use the first union field and would not allow you to change it. The code, while it had the field names, was very misleading because these names could be completely wrong. This is what we have on the left sample.

The new version is much better in this aspect. First, it tries to determine the best union field using several heuristic rules. It checks the disassembly listing for 'structure offset' operands, checks the current context to select the best fit union field. In many cases no user intervention is required. However, if the decompiler fails to pick the corrent union field, the user can always correct it by selecting the desired union field manually. Even complex situations like a union with another nested union or structure are supported. Anonymous nested unions are represented correctly too.

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
   PIO_STACK_LOCATION _stacklocation; // [sp+10h] [bp-14h]@1

  if ( stacklocation->Parameters.DeviceIoControl.IoControlCode == 0x224010 )
  {
    v8 = stacklocation->Parameters.Create.Options == 20;
    Semaphore = 0;
    if ( !v8 )
      goto LABEL_18;
    if ( stacklocation->Parameters.Read.Length < 1 )
      goto LABEL_87;
    buf = Irp->AssociatedIrp.SystemBuffer;
    v33 = &Semaphore;
    v32 = stacklocation->FileObject;
    memcpy(&v27, buf, 0x14u);
    DeviceObjecta = ChanMgrGetByHandleAndFileObject(v27, v28, v29, v30, v31, v32, &Semaphore);
    if ( DeviceObjecta < 0 )
      goto LABEL_92;
    v24 = Irp->AssociatedIrp.SystemBuffer;
    v33 = &v36;
    v32 = stacklocation->Parameters.DeviceIoControl.OutputBufferLength;
    v6 = ChannelIRead(Semaphore, v24, v32, &v36);
LABEL_90:
    v33 = Semaphore;
    goto LABEL_91;
  }
  if ( stacklocation->Parameters.DeviceIoControl.IoControlCode == 2244628 )
  {
    v8 = stacklocation->Parameters.DeviceIoControl.InputBufferLength == 20;
    Semaphore = 0;
    if ( v8 && stacklocation->Parameters.DeviceIoControl.OutputBufferLength == 1 )
    {
      v22 = Irp->AssociatedIrp.SystemBuffer;
```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python
  PIO_STACK_LOCATION _stacklocation; // [sp+10h] [bp-14h]@1

  if ( *&stacklocation->Parameters.Create.FileAttributes == 0x224010 )
  {
    v8 = stacklocation->Parameters.Create.Options == 20;
    Semaphore = 0;
    if ( !v8 )
      goto LABEL_18;
    if ( stacklocation->Parameters.Create.SecurityContext < 1 )
      goto LABEL_87;
    v23 = Irp->AssociatedIrp.MasterIrp;
    v33 = &Semaphore;
    v32 = stacklocation->FileObject;
    memcpy(&v27, v23, 0x14u);
    DeviceObjecta = ChanMgrGetByHandleAndFileObject(v27, v28, v29, v30, v31, v32, &Semaphore);
    if ( DeviceObjecta < 0 )
      goto LABEL_92;
    v24 = Irp->AssociatedIrp.MasterIrp;
    v33 = &v36;
    v32 = stacklocation->Parameters.Create.SecurityContext;
    v6 = ChannelIRead(Semaphore, v24, v32, &v36);
LABEL_90:
    v33 = Semaphore;
    goto LABEL_91;
  }
  if ( *&stacklocation->Parameters.Create.FileAttributes == 2244628 )
  {
    v8 = stacklocation->Parameters.Create.Options == 20;
    Semaphore = 0;
    if ( v8 && stacklocation->Parameters.Create.SecurityContext == 1 )
    {
      v22 = Irp->AssociatedIrp.MasterIrp;
```

{% endtab %}
{% endtabs %}

### Support for merged calls

There is a common compiler optimization that reuses the same call instruction for different calls. Of the left side, the WinHelpA() call is used in two different situations. The decompiler had to use a `goto` statement because it could not represent the code with [structured programming](http://en.wikipedia.org/wiki/Structured_programming) constructs.

The new version unmerged the call and got rid of the `goto` statement. Isn't it nice?

{% tabs %}
{% tab title="PSEUDOCODE V1.6" %}

```javascript
INT_PTR __stdcall EditBinaryValueDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPHELPINFO hinfo)
{
  LONG v5; // eax@8                                                                   

  if ( uMsg == WM_HELP )
  {
    WinHelpW(hinfo->hItemHandle, g_pHelpFileName, HELP_WM_HELP, (ULONG_PTR)s_EditBinaryValueHelpIDs);
  }
  else
  {
    if ( uMsg == WM_CONTEXTMENU )
    {
      WinHelpW((HWND)wParam, g_pHelpFileName, HELP_CONTEXTMENU, (ULONG_PTR)s_EditBinaryValueHelpIDs);
    }
    else
    {
      if ( uMsg == WM_INITDIALOG )
        return EditBinaryValue_OnInitDialog(hwndDlg, wParam, (LONG)hinfo);
      if ( uMsg != 273 || (signed int)(unsigned __int16)wParam <= 0 || (signed int)(unsigned __int16)wParam > 2 )
        return 0;
      v5 = GetWindowLongW(hwndDlg, 8);
      *(_DWORD *)(v5 + 8) = dword_105A048;
      *(_DWORD *)(v5 + 4) = hMem;
      hMem = 0;
      EndDialog(hwndDlg, (unsigned __int16)wParam);
    }
  }
  return 1;
}

```

{% endtab %}

{% tab title="PSEUDOCODE V1.5" %}

```python

INT_PTR __stdcall EditBinaryValueDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPHELPINFO hinfo)
{
  LONG v5; // eax@8                                                                             
  HWND v6; // [sp-10h] [bp-14h]@10                                                              
  const WCHAR *v7; // [sp-Ch] [bp-10h]@10                                                       
  UINT v8; // [sp-8h] [bp-Ch]@10                                                                
  ULONG_PTR v9; // [sp-4h] [bp-8h]@10                                                           

  if ( uMsg == WM_HELP )
  {
    v9 = (ULONG_PTR)s_EditBinaryValueHelpIDs;
    v8 = HELP_WM_HELP;
    v7 = g_pHelpFileName;
    v6 = hinfo->hItemHandle;
    goto LABEL_12;
  }
  if ( uMsg == WM_CONTEXTMENU )
  {
    v9 = (ULONG_PTR)s_EditBinaryValueHelpIDs;
    v8 = HELP_CONTEXTMENU;
    v7 = g_pHelpFileName;
    v6 = (HWND)wParam;
LABEL_12:
    WinHelpW(v6, v7, v8, v9);
    return 1;
  }
  if ( uMsg == WM_INITDIALOG )
    return EditBinaryValue_OnInitDialog(hwndDlg, wParam, (LONG)hinfo);
  if ( uMsg != 273 || (signed int)(unsigned __int16)wParam <= 0 || (signed int)(unsigned __int16)wParam > 2 )
    return 0;
  v5 = GetWindowLongW(hwndDlg, 8);
  *(_DWORD *)(v5 + 8) = dword_105A048;
  *(_DWORD *)(v5 + 4) = hMem;
  hMem = 0;
  EndDialog(hwndDlg, (unsigned __int16)wParam);
  return 1;
}
```

{% endtab %}
{% endtabs %}
