From 8031739110555868e596aa9118f25d9b11287caa Mon Sep 17 00:00:00 2001 From: thisismy-github <48284263+thisismy-github@users.noreply.github.com> Date: Thu, 19 Aug 2021 18:52:06 -0400 Subject: [PATCH] Added option to customize Pinned folder location Items can be pinned to directories that require administative privileges (such as Open-Shell's default installation directory), so long as users take ownership of the pinned folder. Also adds a command to Open-Shell's context menu that opens the current pinned folder. Adds general support for directory-based settings by creating a new setting type called TYPE_DIRECTORY which uses a new bool added to BrowseLinkHelper, called bFoldersOnly. START_MENU_PINNED_ROOT has been removed, and all instances of both it and BrowseLinkHelper have been adjusted accordingly. To create your own directory-based settings, use CSetting::TYPE_DIRECTORY. Empty directory paths are reset to their default value as they can cause unexpected behavior. --- Src/ClassicExplorer/SettingsUI.cpp | 2 +- Src/Lib/Settings.cpp | 10 +-- Src/Lib/Settings.h | 1 + Src/Lib/SettingsUIHelper.cpp | 71 +++++++++++++++---- Src/Lib/SettingsUIHelper.h | 2 +- Src/StartMenu/StartMenuDLL/ItemManager.cpp | 5 +- Src/StartMenu/StartMenuDLL/ItemManager.h | 1 - Src/StartMenu/StartMenuDLL/MenuContainer.cpp | 6 +- Src/StartMenu/StartMenuDLL/SearchManager.cpp | 3 +- Src/StartMenu/StartMenuDLL/SettingsUI.cpp | 5 +- Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp | 13 ++++ Src/StartMenu/StartMenuDLL/StartMenuDLL.rc | 4 +- Src/StartMenu/StartMenuDLL/resource.h | 2 + .../StartMenuHelper/StartMenuExt.cpp | 2 +- Src/StartMenu/StartMenuHelper/dllmain.cpp | 1 + 15 files changed, 99 insertions(+), 29 deletions(-) diff --git a/Src/ClassicExplorer/SettingsUI.cpp b/Src/ClassicExplorer/SettingsUI.cpp index f70b77a..8be0eed 100644 --- a/Src/ClassicExplorer/SettingsUI.cpp +++ b/Src/ClassicExplorer/SettingsUI.cpp @@ -380,7 +380,7 @@ LRESULT CEditToolbarDlg::OnBrowseLink( WORD wNotifyCode, WORD wID, HWND hWndCtl, { wchar_t text[_MAX_PATH]; GetDlgItemText(IDC_COMBOLINK,text,_countof(text)); - if (BrowseLinkHelper(m_hWnd,text)) + if (BrowseLinkHelper(m_hWnd,text,false)) { SetDlgItemText(IDC_COMBOLINK,text); SendMessage(WM_COMMAND,MAKEWPARAM(IDC_COMBOLINK,CBN_KILLFOCUS)); diff --git a/Src/Lib/Settings.cpp b/Src/Lib/Settings.cpp index fb312fc..00903e8 100644 --- a/Src/Lib/Settings.cpp +++ b/Src/Lib/Settings.cpp @@ -125,7 +125,7 @@ bool CSetting::IsEnabled( void ) const if (operation=='>' && pSetting->GetValue().intVal<=val) return false; } - if ((pSetting->type==CSetting::TYPE_STRING || pSetting->type==CSetting::TYPE_BITMAP || pSetting->type==CSetting::TYPE_BITMAP_JPG) && pSetting->GetValue().vt==VT_BSTR) + if ((pSetting->type==CSetting::TYPE_STRING || pSetting->type==CSetting::TYPE_BITMAP || pSetting->type==CSetting::TYPE_BITMAP_JPG || pSetting->type==CSetting::TYPE_DIRECTORY) && pSetting->GetValue().vt==VT_BSTR) { if (operation=='~' && *pSetting->GetValue().bstrVal==0) return false; @@ -202,7 +202,7 @@ bool CSetting::ReadValue( CRegKey ®Key, const wchar_t *valName ) } // string - if (type>=CSetting::TYPE_STRING && type=CSetting::TYPE_STRING && type!=CSetting::TYPE_MULTISTRING) { ULONG len; if (regKey.QueryStringValue(valName,NULL,&len)==ERROR_SUCCESS) @@ -2221,7 +2221,7 @@ bool GetSettingBool( const CSetting &setting ) CString GetSettingString( const CSetting &setting ) { - Assert(setting.type==CSetting::TYPE_STRING); + Assert(setting.type==CSetting::TYPE_STRING || setting.type==CSetting::TYPE_DIRECTORY); if (setting.value.vt!=VT_BSTR) return CString(); return setting.value.bstrVal; @@ -2722,7 +2722,7 @@ bool SaveAdmx( TSettingsComponent component, const char *admxFile, const char *a { fprintf_s(fAdmx,"\t\t\t\t\r\n",pSetting->name); } - else if (pSetting->type==CSetting::TYPE_STRING || pSetting->type==CSetting::TYPE_ICON || pSetting->type==CSetting::TYPE_BITMAP || pSetting->type==CSetting::TYPE_BITMAP_JPG || pSetting->type==CSetting::TYPE_SOUND || pSetting->type==CSetting::TYPE_FONT) + else if (pSetting->type==CSetting::TYPE_STRING || pSetting->type==CSetting::TYPE_ICON || pSetting->type==CSetting::TYPE_BITMAP || pSetting->type==CSetting::TYPE_BITMAP_JPG || pSetting->type==CSetting::TYPE_SOUND || pSetting->type==CSetting::TYPE_FONT || pSetting->type==CSetting::TYPE_DIRECTORY) { fprintf_s(fAdmx,"\t\t\t\t\r\n",pSetting->name); } @@ -2782,7 +2782,7 @@ bool SaveAdmx( TSettingsComponent component, const char *admxFile, const char *a { fprintf_s(fAdml,"\t\t\t\t%s\r\n",(const char*)name); } - else if (pSetting->type==CSetting::TYPE_STRING || pSetting->type==CSetting::TYPE_ICON || pSetting->type==CSetting::TYPE_BITMAP || pSetting->type==CSetting::TYPE_BITMAP_JPG || pSetting->type==CSetting::TYPE_SOUND || pSetting->type==CSetting::TYPE_FONT) + else if (pSetting->type==CSetting::TYPE_STRING || pSetting->type==CSetting::TYPE_ICON || pSetting->type==CSetting::TYPE_BITMAP || pSetting->type==CSetting::TYPE_BITMAP_JPG || pSetting->type==CSetting::TYPE_SOUND || pSetting->type==CSetting::TYPE_FONT || pSetting->type==CSetting::TYPE_DIRECTORY) { fprintf_s(fAdml,"\t\t\t\t\r\n",(const char*)name); } diff --git a/Src/Lib/Settings.h b/Src/Lib/Settings.h index 0306a85..fd945e2 100644 --- a/Src/Lib/Settings.h +++ b/Src/Lib/Settings.h @@ -32,6 +32,7 @@ struct CSetting TYPE_SOUND, TYPE_FONT, TYPE_MULTISTRING, + TYPE_DIRECTORY, }; enum diff --git a/Src/Lib/SettingsUIHelper.cpp b/Src/Lib/SettingsUIHelper.cpp index 0c32212..5c22f58 100644 --- a/Src/Lib/SettingsUIHelper.cpp +++ b/Src/Lib/SettingsUIHelper.cpp @@ -1216,7 +1216,7 @@ bool BrowseCommandHelper( HWND parent, wchar_t *text ) return false; } -bool BrowseLinkHelper( HWND parent, wchar_t *text ) +bool BrowseLinkHelper( HWND parent, wchar_t *text, bool bFoldersOnly ) { DoEnvironmentSubst(text,_MAX_PATH); @@ -1227,16 +1227,22 @@ bool BrowseLinkHelper( HWND parent, wchar_t *text ) if (!pCustomize) return false; - pDialog->SetTitle(LoadStringEx(IDS_PICK_LINK_TITLE)); - pDialog->SetOkButtonLabel(LoadStringEx(IDS_PICK_LINK_FILE)); - wchar_t button[256]; - Sprintf(button,_countof(button),L" %s ",LoadStringEx(IDS_PICK_LINK_FOLDER)); - pCustomize->AddPushButton(101,button); + pDialog->SetTitle(LoadStringEx(bFoldersOnly?IDS_PICK_LINK_FOLDER:IDS_PICK_LINK_TITLE)); + if (!bFoldersOnly) // add separate buttons for selecting files/folders to the dialog + { + pDialog->SetOkButtonLabel(LoadStringEx(IDS_PICK_LINK_FILE)); + wchar_t button[256]; + Sprintf(button,_countof(button),L" %s ",LoadStringEx(IDS_PICK_LINK_FOLDER)); + pCustomize->AddPushButton(101,button); + } CBrowseLinkEvents events; DWORD cookie; pDialog->Advise(&events,&cookie); - pDialog->SetOptions(FOS_ALLNONSTORAGEITEMS|FOS_FILEMUSTEXIST|FOS_DONTADDTORECENT|FOS_DEFAULTNOMINIMODE|FOS_NODEREFERENCELINKS); + if (bFoldersOnly) // set FOS_PICKFOLDERS option to use dialog in folder-only mode + pDialog->SetOptions(FOS_PICKFOLDERS|FOS_ALLNONSTORAGEITEMS|FOS_DONTADDTORECENT|FOS_DEFAULTNOMINIMODE); + else + pDialog->SetOptions(FOS_ALLNONSTORAGEITEMS|FOS_FILEMUSTEXIST|FOS_DONTADDTORECENT|FOS_DEFAULTNOMINIMODE|FOS_NODEREFERENCELINKS); { const wchar_t *c=wcschr(text,'|'); if (c) @@ -2274,6 +2280,7 @@ public: EDIT_HOTKEY_ANY, EDIT_COLOR, EDIT_FONT, + EDIT_DIRECTORY, }; BEGIN_MSG_MAP( CTreeSettingsDlg ) @@ -2717,6 +2724,29 @@ LRESULT CTreeSettingsDlg::OnBrowse( WORD wNotifyCode, WORD wID, HWND hWndCtl, BO m_EditBox.SetFocus(); m_bIgnoreFocus=false; } + else if (m_EditMode==EDIT_DIRECTORY) + { + m_bIgnoreFocus=true; + CString str; + m_EditBox.GetWindowText(str); + str.TrimLeft(); str.TrimRight(); + wchar_t text[1024]; + DWORD dwAttrs=GetFileAttributes(str); // ensure directory exists before passing it to dialog + if (dwAttrs!=INVALID_FILE_ATTRIBUTES && dwAttrs&FILE_ATTRIBUTE_DIRECTORY) + { + Strcpy(text,_countof(text),str); + DoEnvironmentSubst(text,_countof(text)); + } + else + text[0]=0; + Strcpy(text,_countof(text),str); + DoEnvironmentSubst(text,_countof(text)); + if (BrowseLinkHelper(m_hWnd,text,true)) + m_EditBox.SetWindowText(text); + SendMessage(WM_NEXTDLGCTL,(LPARAM)m_EditBox.m_hWnd,TRUE); + m_EditBox.SetFocus(); + m_bIgnoreFocus=false; + } return 0; } @@ -3052,6 +3082,20 @@ void CTreeSettingsDlg::ApplyEditBox( void ) pSetting->flags&=~CSetting::FLAG_DEFAULT; } } + else if (pSetting->type==CSetting::TYPE_DIRECTORY) + { + if (pSetting->value.vt!=VT_BSTR || str!=pSetting->value.bstrVal) + { + if (str.IsEmpty()) // empty directory strings cause unexpected behavior, so we reset to avoid this + pSetting->value=pSetting->defValue; + else // otherwise we are very lenient about what users can input as a path + pSetting->value=CComVariant(str); + if (pSetting->value==pSetting->defValue) + pSetting->flags|=CSetting::FLAG_DEFAULT; + else + pSetting->flags&=~CSetting::FLAG_DEFAULT; + } + } else { if (pSetting->value.vt!=VT_BSTR || str!=pSetting->value.bstrVal) @@ -3095,7 +3139,7 @@ void CTreeSettingsDlg::ItemSelected( HTREEITEM hItem, CSetting *pSetting, bool b val=valVar.intVal; Sprintf(text,_countof(text),L"%d",val); } - else if (pSetting->type==CSetting::TYPE_STRING || pSetting->type==CSetting::TYPE_ICON || pSetting->type==CSetting::TYPE_BITMAP || pSetting->type==CSetting::TYPE_BITMAP_JPG || pSetting->type==CSetting::TYPE_SOUND || pSetting->type==CSetting::TYPE_FONT) + else if (pSetting->type==CSetting::TYPE_STRING || pSetting->type==CSetting::TYPE_ICON || pSetting->type==CSetting::TYPE_BITMAP || pSetting->type==CSetting::TYPE_BITMAP_JPG || pSetting->type==CSetting::TYPE_SOUND || pSetting->type==CSetting::TYPE_FONT || pSetting->type==CSetting::TYPE_DIRECTORY) { if (valVar.vt==VT_BSTR) Strcpy(text,_countof(text),valVar.bstrVal); @@ -3111,8 +3155,10 @@ void CTreeSettingsDlg::ItemSelected( HTREEITEM hItem, CSetting *pSetting, bool b mode=EDIT_BITMAP_JPG; else if (pSetting->type==CSetting::TYPE_SOUND) mode=EDIT_SOUND; - else + else if (pSetting->type==CSetting::TYPE_FONT) mode=EDIT_FONT; + else + mode=EDIT_DIRECTORY; } else if (pSetting->type==CSetting::TYPE_HOTKEY || pSetting->type==CSetting::TYPE_HOTKEY_ANY) { @@ -3152,7 +3198,7 @@ void CTreeSettingsDlg::ItemSelected( HTREEITEM hItem, CSetting *pSetting, bool b m_pEditSetting=pSetting; } - if (mode==EDIT_ICON || mode==EDIT_BITMAP || mode==EDIT_BITMAP_JPG || mode==EDIT_SOUND || mode==EDIT_FONT || mode==EDIT_COLOR) + if (mode==EDIT_ICON || mode==EDIT_BITMAP || mode==EDIT_BITMAP_JPG || mode==EDIT_SOUND || mode==EDIT_FONT || mode==EDIT_COLOR || mode==EDIT_DIRECTORY) { RECT rc2=rc; int width=(rc2.bottom-rc2.top)*3/2; @@ -3210,14 +3256,15 @@ void CTreeSettingsDlg::UpdateEditPosition( void ) DeleteDC(hdc); DWORD margins=(DWORD)m_EditBox.SendMessage(EM_GETMARGINS); size.cx+=HIWORD(margins)+LOWORD(margins)+12; - if (m_EditMode==EDIT_ICON || m_EditMode==EDIT_BITMAP || m_EditMode==EDIT_BITMAP_JPG || m_EditMode==EDIT_FONT || m_EditMode==EDIT_COLOR) + // adjust size and position of edit boxes for settings that use browse/play buttons + if (m_EditMode==EDIT_ICON || m_EditMode==EDIT_BITMAP || m_EditMode==EDIT_BITMAP_JPG || m_EditMode==EDIT_FONT || m_EditMode==EDIT_COLOR || m_EditMode==EDIT_DIRECTORY) size.cx+=width; if (m_EditMode==EDIT_SOUND) size.cx+=width*2; if (size.cx pFolder; if (SUCCEEDED(SHCreateItemFromParsingName(path,NULL,IID_IShellItem,(void**)&pFolder))) diff --git a/Src/StartMenu/StartMenuDLL/SettingsUI.cpp b/Src/StartMenu/StartMenuDLL/SettingsUI.cpp index 98f563f..008a009 100644 --- a/Src/StartMenu/StartMenuDLL/SettingsUI.cpp +++ b/Src/StartMenu/StartMenuDLL/SettingsUI.cpp @@ -1742,7 +1742,7 @@ LRESULT CEditMenuDlg::OnBrowseLink( WORD wNotifyCode, WORD wID, HWND hWndCtl, BO { wchar_t text[_MAX_PATH]; GetDlgItemText(IDC_COMBOLINK,text,_countof(text)); - if (BrowseLinkHelper(m_hWnd,text)) + if (BrowseLinkHelper(m_hWnd,text,false)) { SetDlgItemText(IDC_COMBOLINK,text); SendMessage(WM_COMMAND,MAKEWPARAM(IDC_COMBOLINK,CBN_KILLFOCUS)); @@ -2437,7 +2437,7 @@ LRESULT CEditMenuDlg7::OnBrowseLink( WORD wNotifyCode, WORD wID, HWND hWndCtl, B { wchar_t text[_MAX_PATH]; GetDlgItemText(IDC_EDITLINK2,text,_countof(text)); - if (BrowseLinkHelper(m_hWnd,text)) + if (BrowseLinkHelper(m_hWnd,text,false)) { SetDlgItemText(IDC_EDITLINK2,text); SendMessage(WM_COMMAND,MAKEWPARAM(IDC_EDITLINK2,EN_KILLFOCUS)); @@ -4280,6 +4280,7 @@ CSetting g_Settings[]={ {L"PinnedPrograms",CSetting::TYPE_INT,IDS_PINNED_PROGRAMS,IDS_PINNED_PROGRAMS_TIP,PINNED_PROGRAMS_PINNED}, {L"FastItems",CSetting::TYPE_RADIO,IDS_FAST_ITEMS,IDS_FAST_ITEMS_TIP}, {L"PinnedItems",CSetting::TYPE_RADIO,IDS_PINNED_ITEMS,IDS_PINNED_ITEMS_TIP}, + {L"PinnedItemsPath",CSetting::TYPE_DIRECTORY,IDS_PINNED_PATH,IDS_PINNED_PATH_TIP,L"%APPDATA%\\OpenShell\\Pinned",0,L"PinnedPrograms=1",L"PinnedItems"}, {L"RecentPrograms",CSetting::TYPE_INT,IDS_RECENT_PROGRAMS,IDS_RECENT_PROGRAMS_TIP,RECENT_PROGRAMS_RECENT,CSetting::FLAG_BASIC}, {L"None",CSetting::TYPE_RADIO,IDS_NO_RECENT,IDS_NO_RECENT_TIP}, {L"Recent",CSetting::TYPE_RADIO,IDS_SHOW_RECENT,IDS_SHOW_RECENT_TIP}, diff --git a/Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp b/Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp index feef645..e1aa81a 100644 --- a/Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp +++ b/Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp @@ -3856,6 +3856,7 @@ if (!g_bTrimHooks) CMD_OPEN, CMD_OPEN_ALL, CMD_EXPLORER, + CMD_OPEN_PINNED, }; // right-click on the start button - open the context menu (Settings, Help, Exit) @@ -3876,6 +3877,8 @@ if (!g_bTrimHooks) AppendMenu(menu,MF_STRING,CMD_OPEN,FindTranslation(L"Menu.Open",L"&Open")); if (!SHRestricted(REST_NOCOMMONGROUPS)) AppendMenu(menu,MF_STRING,CMD_OPEN_ALL,FindTranslation(L"Menu.OpenAll",L"O&pen All Users")); + if (GetSettingInt(L"PinnedPrograms")==PINNED_PROGRAMS_PINNED) + AppendMenu(menu,MF_STRING,CMD_OPEN_PINNED,FindTranslation(L"Menu.OpenPinned",L"O&pen Pinned")); AppendMenu(menu,MF_SEPARATOR,0,0); } if (GetSettingBool(L"EnableSettings")) @@ -3922,6 +3925,16 @@ if (!g_bTrimHooks) if (SUCCEEDED(ShGetKnownFolderPath((res==CMD_OPEN)?FOLDERID_StartMenu:FOLDERID_CommonStartMenu,&pPath))) ShellExecute(NULL,L"open",pPath,NULL,NULL,SW_SHOWNORMAL); } + if (res==CMD_OPEN_PINNED) // open pinned folder + { + SHELLEXECUTEINFO execute={sizeof(execute)}; + CString path=GetSettingString(L"PinnedItemsPath"); + execute.lpVerb=L"open"; + execute.lpFile=path; + execute.nShow=SW_SHOWNORMAL; + execute.fMask=SEE_MASK_DOENVSUBST; + ShellExecuteEx(&execute); + } if (res==CMD_EXPLORER) { CString path=GetSettingString(L"ExplorerPath"); diff --git a/Src/StartMenu/StartMenuDLL/StartMenuDLL.rc b/Src/StartMenu/StartMenuDLL/StartMenuDLL.rc index 57feae1..6ca0538 100644 --- a/Src/StartMenu/StartMenuDLL/StartMenuDLL.rc +++ b/Src/StartMenu/StartMenuDLL/StartMenuDLL.rc @@ -1044,7 +1044,7 @@ BEGIN IDS_FOLDERS_FIRST "Show folders first" IDS_FOLDERS_FIRST_TIP "When this is checked, the All Programs tree will show the folders first and the programs last" IDS_PINNED_PROGRAMS "Pinned Programs folder" - IDS_PINNED_PROGRAMS_TIP "Select the location to store the pinned programs" + IDS_PINNED_PROGRAMS_TIP "Select the location to store pinned programs. After updating this setting, close this window in order to pin items through the context menu again" IDS_FAST_ITEMS "Use Start Menu folder" END @@ -1319,6 +1319,8 @@ STRINGTABLE BEGIN IDS_OPEN_TRUE_PATH "Open pinned folders to their true path" IDS_OPEN_TRUE_PATH_TIP "When this is checked, pinned folders will open to their true path instead of the path to their shortcut in the Pinned Programs folder" + IDS_PINNED_PATH "Pinned folder path" + IDS_PINNED_PATH_TIP "The path to use as the Pinned folder. If the path does not exist, it will be created (if possible) after opening the start menu. Close this window after updating this setting to update your context menu.\n\nNote: If you do not have permissions for the selected path, you will not be able to pin items until you take ownership of the new folder" END #endif // English (U.S.) resources diff --git a/Src/StartMenu/StartMenuDLL/resource.h b/Src/StartMenu/StartMenuDLL/resource.h index e5fa099..ea11543 100644 --- a/Src/StartMenu/StartMenuDLL/resource.h +++ b/Src/StartMenu/StartMenuDLL/resource.h @@ -778,6 +778,8 @@ #define IDS_ITEM_LINKS_TIP 3681 #define IDS_OPEN_TRUE_PATH 3682 #define IDS_OPEN_TRUE_PATH_TIP 3683 +#define IDS_PINNED_PATH 3684 +#define IDS_PINNED_PATH_TIP 3685 #define IDS_STRING7001 7001 #define IDS_STRING7002 7002 #define IDS_STRING7003 7003 diff --git a/Src/StartMenu/StartMenuHelper/StartMenuExt.cpp b/Src/StartMenu/StartMenuHelper/StartMenuExt.cpp index 10a3b30..5cf4aff 100644 --- a/Src/StartMenu/StartMenuHelper/StartMenuExt.cpp +++ b/Src/StartMenu/StartMenuHelper/StartMenuExt.cpp @@ -91,7 +91,7 @@ STDMETHODIMP CStartMenuExt::Initialize( PCIDLIST_ABSOLUTE pidlFolder, IDataObjec bUsePinned=(setting==1); if (bUsePinned) { - Strcpy(m_PinFolder1,_countof(m_PinFolder1),L"%APPDATA%\\OpenShell\\Pinned\\"); + Sprintf(m_PinFolder1,_countof(m_PinFolder1),L"%s\\",GetSettingString(L"PinnedItemsPath")); DoEnvironmentSubst(m_PinFolder1,_countof(m_PinFolder1)); m_PinFolder2[0]=0; } diff --git a/Src/StartMenu/StartMenuHelper/dllmain.cpp b/Src/StartMenu/StartMenuHelper/dllmain.cpp index 10c2ced..795032a 100644 --- a/Src/StartMenu/StartMenuHelper/dllmain.cpp +++ b/Src/StartMenu/StartMenuHelper/dllmain.cpp @@ -57,6 +57,7 @@ CSetting g_Settings[]={ {L"DisablePinExt",CSetting::TYPE_BOOL,0,0,0}, {L"FolderStartMenu",CSetting::TYPE_STRING,0,0,L""}, {L"FolderCommonStartMenu",CSetting::TYPE_STRING,0,0,L""}, + {L"PinnedItemsPath",CSetting::TYPE_DIRECTORY,0,0,L"%APPDATA%\\OpenShell\\Pinned"}, {L"Language",CSetting::TYPE_GROUP}, {L"Language",CSetting::TYPE_STRING,0,0,L"",CSetting::FLAG_COLD|CSetting::FLAG_SHARED},