mirror of
https://github.com/reactos/reactos.git
synced 2024-07-06 20:55:16 +00:00
Sync to Wine-0_9_5:
Francois Gouget <fgouget@free.fr> - Small documentation tweaks to avoid winapi_check warnings. Mike McCormack <mike@codeweavers.com> - msi: Change some FIXME messages to comments. - msi: Add stub actions for CCPSearch and RMCCPSearch. - msi: Fixes for the MaskedEdit control. Allow MaskedEdit masks that aren't enclosed with <>. Allow the MaskedEdit's edit controls to scroll a bit in case things don't line up. - msi: Subclass the Richedit control. Send a "DoAction" control event when the user scrolls the text. - msi: Implement the Reset control event. - MSI: Improve the MsiGetMode stub a little. - msi: Add a stub for MsiGetLastErrorRecord. - msi: Define the property "Intel" if we're running on an Intel processor. - msi: Apply any MSI transforms specified by the TRANSFORMS property. Marcus Meissner <marcus@jet.franken.de> - msi: Report the commandline that failed to start in ERR()s. svn path=/trunk/; revision=20620
This commit is contained in:
parent
95f799abe6
commit
c5c5674029
|
@ -569,6 +569,30 @@ static UINT msi_apply_patches( MSIPACKAGE *package )
|
|||
return r;
|
||||
}
|
||||
|
||||
static UINT msi_apply_transforms( MSIPACKAGE *package )
|
||||
{
|
||||
static const WCHAR szTransforms[] = {
|
||||
'T','R','A','N','S','F','O','R','M','S',0 };
|
||||
LPWSTR xform_list, *xforms;
|
||||
UINT i, r = ERROR_SUCCESS;
|
||||
|
||||
xform_list = msi_dup_property( package, szTransforms );
|
||||
xforms = msi_split_string( xform_list, ';' );
|
||||
|
||||
for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
|
||||
{
|
||||
if (xforms[i][0] == ':')
|
||||
r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
|
||||
else
|
||||
r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
|
||||
}
|
||||
|
||||
msi_free( xforms );
|
||||
msi_free( xform_list );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
* TOP level entry points
|
||||
*****************************************************/
|
||||
|
@ -618,6 +642,7 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
|
|||
|
||||
msi_parse_command_line( package, szCommandLine );
|
||||
|
||||
msi_apply_transforms( package );
|
||||
msi_apply_patches( package );
|
||||
|
||||
if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
|
||||
|
@ -3096,7 +3121,7 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
|
|||
}
|
||||
msi_free(buffer);
|
||||
|
||||
FIXME("Need to write more keys to the user registry\n");
|
||||
/* FIXME: Need to write more keys to the user registry */
|
||||
|
||||
hDb= alloc_msihandle( &package->db->hdr );
|
||||
rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
|
||||
|
@ -3540,7 +3565,7 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
|
|||
return rc;
|
||||
|
||||
/* dump all the info i can grab */
|
||||
FIXME("Flesh out more information\n");
|
||||
/* FIXME: Flesh out more information */
|
||||
|
||||
msi_write_uninstall_property_vals( package, hkey );
|
||||
|
||||
|
@ -3554,7 +3579,7 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
|
|||
RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
|
||||
msi_free(buffer);
|
||||
|
||||
FIXME("Write real Estimated Size when we have it\n");
|
||||
/* FIXME: Write real Estimated Size when we have it */
|
||||
msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
|
||||
|
||||
GetLocalTime(&systime);
|
||||
|
@ -4210,11 +4235,23 @@ static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
|
|||
return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
|
||||
}
|
||||
|
||||
static UINT ACTION_CCPSearch( MSIPACKAGE *package )
|
||||
{
|
||||
static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
|
||||
return msi_unimplemented_action_stub( package, "CCPSearch", table );
|
||||
}
|
||||
|
||||
static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
|
||||
{
|
||||
static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
|
||||
return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
|
||||
}
|
||||
|
||||
static struct _actions StandardActions[] = {
|
||||
{ szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
|
||||
{ szAppSearch, ACTION_AppSearch },
|
||||
{ szBindImage, ACTION_BindImage },
|
||||
{ szCCPSearch, NULL},
|
||||
{ szCCPSearch, ACTION_CCPSearch},
|
||||
{ szCostFinalize, ACTION_CostFinalize },
|
||||
{ szCostInitialize, ACTION_CostInitialize },
|
||||
{ szCreateFolders, ACTION_CreateFolders },
|
||||
|
@ -4266,7 +4303,7 @@ static struct _actions StandardActions[] = {
|
|||
{ szRemoveRegistryValues, NULL},
|
||||
{ szRemoveShortcuts, NULL},
|
||||
{ szResolveSource, ACTION_ResolveSource},
|
||||
{ szRMCCPSearch, NULL},
|
||||
{ szRMCCPSearch, ACTION_RMCCPSearch},
|
||||
{ szScheduleReboot, NULL},
|
||||
{ szSelfRegModules, ACTION_SelfRegModules },
|
||||
{ szSelfUnregModules, ACTION_SelfUnregModules },
|
||||
|
|
|
@ -548,13 +548,14 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
|
|||
rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
|
||||
c_collen, &si, &info);
|
||||
|
||||
msi_free(cmd);
|
||||
|
||||
if ( !rc )
|
||||
{
|
||||
ERR("Unable to execute command\n");
|
||||
ERR("Unable to execute command %s\n", debugstr_w(cmd));
|
||||
msi_free(cmd);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
msi_free(cmd);
|
||||
|
||||
prc = process_handle(package, type, info.hThread, info.hProcess, action,
|
||||
&finished);
|
||||
|
@ -609,13 +610,14 @@ static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source,
|
|||
rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
|
||||
c_collen, &si, &info);
|
||||
|
||||
msi_free(cmd);
|
||||
|
||||
if ( !rc )
|
||||
{
|
||||
ERR("Unable to execute command\n");
|
||||
ERR("Unable to execute command %s\n", debugstr_w(cmd));
|
||||
msi_free(cmd);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
msi_free(cmd);
|
||||
|
||||
prc = process_handle(package, type, info.hThread, info.hProcess, action,
|
||||
NULL);
|
||||
|
@ -694,13 +696,14 @@ static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source,
|
|||
rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
|
||||
c_collen, &si, &info);
|
||||
|
||||
msi_free(cmd);
|
||||
|
||||
if ( !rc )
|
||||
{
|
||||
ERR("Unable to execute command\n");
|
||||
ERR("Unable to execute command %s\n", debugstr_w(cmd));
|
||||
msi_free(cmd);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
msi_free(cmd);
|
||||
|
||||
return process_handle(package, type, info.hThread, info.hProcess, action, NULL);
|
||||
}
|
||||
|
@ -733,13 +736,14 @@ static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
|
|||
|
||||
rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL,
|
||||
c_collen, &si, &info);
|
||||
msi_free(deformated);
|
||||
|
||||
if ( !rc )
|
||||
{
|
||||
ERR("Unable to execute command\n");
|
||||
ERR("Unable to execute command %s\n", debugstr_w(deformated));
|
||||
msi_free(deformated);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
msi_free(deformated);
|
||||
|
||||
prc = process_handle(package, type, info.hThread, info.hProcess, action,
|
||||
NULL);
|
||||
|
|
|
@ -59,7 +59,6 @@ struct msi_control_tag
|
|||
HBITMAP hBitmap;
|
||||
HICON hIcon;
|
||||
LPWSTR tabnext;
|
||||
HMODULE hDll;
|
||||
WCHAR name[1];
|
||||
};
|
||||
|
||||
|
@ -329,7 +328,6 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog,
|
|||
control->value = NULL;
|
||||
control->hBitmap = NULL;
|
||||
control->hIcon = NULL;
|
||||
control->hDll = NULL;
|
||||
control->tabnext = strdupW( MSI_RecordGetString( rec, 11) );
|
||||
|
||||
x = MSI_RecordGetInteger( rec, 4 );
|
||||
|
@ -695,6 +693,42 @@ static UINT msi_dialog_line_control( msi_dialog *dialog, MSIRECORD *rec )
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/******************** Scroll Text ********************************************/
|
||||
|
||||
struct msi_scrolltext_info
|
||||
{
|
||||
msi_dialog *dialog;
|
||||
msi_control *control;
|
||||
WNDPROC oldproc;
|
||||
HMODULE hRichedit;
|
||||
};
|
||||
|
||||
static LRESULT WINAPI
|
||||
MSIScrollText_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
struct msi_scrolltext_info *info;
|
||||
HRESULT r;
|
||||
|
||||
TRACE("%p %04x %08x %08lx\n", hWnd, msg, wParam, lParam);
|
||||
|
||||
info = GetPropW( hWnd, szButtonData );
|
||||
|
||||
r = CallWindowProcW( info->oldproc, hWnd, msg, wParam, lParam );
|
||||
|
||||
switch( msg )
|
||||
{
|
||||
case WM_NCDESTROY:
|
||||
FreeLibrary( info->hRichedit );
|
||||
msi_free( info );
|
||||
RemovePropW( hWnd, szButtonData );
|
||||
break;
|
||||
case WM_VSCROLL:
|
||||
msi_dialog_button_handler( info->dialog, info->control, BN_CLICKED );
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
struct msi_streamin_info
|
||||
{
|
||||
LPSTR string;
|
||||
|
@ -718,29 +752,11 @@ msi_richedit_stream_in( DWORD_PTR arg, LPBYTE buffer, LONG count, LONG *pcb )
|
|||
return 0;
|
||||
}
|
||||
|
||||
static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec )
|
||||
static void msi_scrolltext_add_text( msi_control *control, LPCWSTR text )
|
||||
{
|
||||
static const WCHAR szRichEdit20W[] = {
|
||||
'R','i','c','h','E','d','i','t','2','0','W',0
|
||||
};
|
||||
struct msi_streamin_info info;
|
||||
msi_control *control;
|
||||
LPCWSTR text;
|
||||
EDITSTREAM es;
|
||||
DWORD style;
|
||||
HMODULE hRichedit;
|
||||
|
||||
hRichedit = LoadLibraryA("riched20");
|
||||
|
||||
style = WS_BORDER | ES_MULTILINE | WS_VSCROLL |
|
||||
ES_READONLY | ES_AUTOVSCROLL | WS_TABSTOP;
|
||||
control = msi_dialog_add_control( dialog, rec, szRichEdit20W, style );
|
||||
if (!control)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
control->hDll = hRichedit;
|
||||
|
||||
text = MSI_RecordGetString( rec, 10 );
|
||||
info.string = strdupWtoA( text );
|
||||
info.offset = 0;
|
||||
info.length = lstrlenA( info.string ) + 1;
|
||||
|
@ -752,6 +768,43 @@ static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec )
|
|||
SendMessageW( control->hwnd, EM_STREAMIN, SF_RTF, (LPARAM) &es );
|
||||
|
||||
msi_free( info.string );
|
||||
}
|
||||
|
||||
static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec )
|
||||
{
|
||||
static const WCHAR szRichEdit20W[] = {
|
||||
'R','i','c','h','E','d','i','t','2','0','W',0
|
||||
};
|
||||
struct msi_scrolltext_info *info;
|
||||
msi_control *control;
|
||||
DWORD style;
|
||||
|
||||
info = msi_alloc( sizeof *info );
|
||||
if (!info)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
info->hRichedit = LoadLibraryA("riched20");
|
||||
|
||||
style = WS_BORDER | ES_MULTILINE | WS_VSCROLL |
|
||||
ES_READONLY | ES_AUTOVSCROLL | WS_TABSTOP;
|
||||
control = msi_dialog_add_control( dialog, rec, szRichEdit20W, style );
|
||||
if (!control)
|
||||
{
|
||||
FreeLibrary( info->hRichedit );
|
||||
msi_free( info );
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
info->dialog = dialog;
|
||||
info->control = control;
|
||||
|
||||
/* subclass the static control */
|
||||
info->oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC,
|
||||
(LONG_PTR)MSIScrollText_WndProc );
|
||||
SetPropW( control->hwnd, szButtonData, info );
|
||||
|
||||
/* add the text into the richedit */
|
||||
msi_scrolltext_add_text( control, MSI_RecordGetString( rec, 10 ) );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -1076,15 +1129,16 @@ static struct msi_maskedit_info * msi_dialog_parse_groups( LPCWSTR mask )
|
|||
if( !mask )
|
||||
return info;
|
||||
|
||||
p = strchrW(mask, '<');
|
||||
if( !p )
|
||||
return info;
|
||||
|
||||
info = msi_alloc_zero( sizeof *info );
|
||||
if( !info )
|
||||
return info;
|
||||
|
||||
p++;
|
||||
p = strchrW(mask, '<');
|
||||
if( p )
|
||||
p++;
|
||||
else
|
||||
p = mask;
|
||||
|
||||
for( i=0; i<MASK_MAX_GROUPS; i++ )
|
||||
{
|
||||
/* stop at the end of the string */
|
||||
|
@ -1124,7 +1178,7 @@ msi_maskedit_create_children( struct msi_maskedit_info *info, LPCWSTR font )
|
|||
HWND hwnd;
|
||||
UINT i;
|
||||
|
||||
style = WS_CHILD | WS_BORDER | WS_VISIBLE | WS_TABSTOP;
|
||||
style = WS_CHILD | WS_BORDER | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL;
|
||||
|
||||
GetClientRect( info->hwnd, &rect );
|
||||
|
||||
|
@ -1512,6 +1566,12 @@ static UINT msi_dialog_evaluate_control_conditions( msi_dialog *dialog )
|
|||
return r;
|
||||
}
|
||||
|
||||
UINT msi_dialog_reset( msi_dialog *dialog )
|
||||
{
|
||||
/* FIXME: should restore the original values of any properties we changed */
|
||||
return msi_dialog_evaluate_control_conditions( dialog );
|
||||
}
|
||||
|
||||
/* figure out the height of 10 point MS Sans Serif */
|
||||
static INT msi_dialog_get_sans_serif_height( HWND hwnd )
|
||||
{
|
||||
|
@ -2138,8 +2198,6 @@ void msi_dialog_destroy( msi_dialog *dialog )
|
|||
DestroyIcon( t->hIcon );
|
||||
msi_free( t->tabnext );
|
||||
msi_free( t );
|
||||
if (t->hDll)
|
||||
FreeLibrary( t->hDll );
|
||||
}
|
||||
|
||||
/* destroy the list of fonts */
|
||||
|
|
|
@ -243,6 +243,13 @@ static UINT ControlEvent_SetTargetPath(MSIPACKAGE* package, LPCWSTR argument,
|
|||
return r;
|
||||
}
|
||||
|
||||
static UINT ControlEvent_Reset(MSIPACKAGE* package, LPCWSTR argument,
|
||||
msi_dialog* dialog)
|
||||
{
|
||||
msi_dialog_reset(dialog);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Subscribed events
|
||||
*/
|
||||
|
@ -371,6 +378,7 @@ struct _events Events[] = {
|
|||
{ "Remove",ControlEvent_Remove },
|
||||
{ "AddSource",ControlEvent_AddSource },
|
||||
{ "SetTargetPath",ControlEvent_SetTargetPath },
|
||||
{ "Reset",ControlEvent_Reset },
|
||||
{ NULL,NULL },
|
||||
};
|
||||
|
||||
|
|
|
@ -449,8 +449,31 @@ UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
|
|||
|
||||
BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
|
||||
{
|
||||
FIXME("STUB (iRunMode=%i)\n",iRunMode);
|
||||
return TRUE;
|
||||
BOOL r = FALSE;
|
||||
|
||||
switch (iRunMode)
|
||||
{
|
||||
case MSIRUNMODE_WINDOWS9X:
|
||||
if (GetVersion() & 0x80000000)
|
||||
r = TRUE;
|
||||
break;
|
||||
|
||||
case MSIRUNMODE_RESERVED11:
|
||||
case MSIRUNMODE_RESERVED14:
|
||||
case MSIRUNMODE_RESERVED15:
|
||||
break;
|
||||
|
||||
case MSIRUNMODE_SCHEDULED:
|
||||
case MSIRUNMODE_ROLLBACK:
|
||||
case MSIRUNMODE_COMMIT:
|
||||
break;
|
||||
|
||||
default:
|
||||
FIXME("%ld %d\n", hInstall, iRunMode);
|
||||
r = TRUE;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -57,7 +57,7 @@ static LONG dll_count;
|
|||
|
||||
static const WCHAR installerW[] = {'\\','I','n','s','t','a','l','l','e','r',0};
|
||||
|
||||
/**********************************************************************
|
||||
/*
|
||||
* Dll lifetime tracking declaration
|
||||
*/
|
||||
static void LockModule(void)
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
45 stdcall MsiEnumProductsW(long ptr)
|
||||
46 stdcall MsiEvaluateConditionA(long str)
|
||||
47 stdcall MsiEvaluateConditionW(long wstr)
|
||||
48 stub MsiGetLastErrorRecord
|
||||
48 stdcall MsiGetLastErrorRecord()
|
||||
49 stdcall MsiGetActiveDatabase(long)
|
||||
50 stdcall MsiGetComponentStateA(long str ptr ptr)
|
||||
51 stdcall MsiGetComponentStateW(long wstr ptr ptr)
|
||||
|
|
|
@ -317,6 +317,8 @@ extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname,
|
|||
|
||||
/* transform functions */
|
||||
extern UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg );
|
||||
extern UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
|
||||
LPCWSTR szTransformFile, int iErrorCond );
|
||||
|
||||
/* action internals */
|
||||
extern UINT MSI_InstallPackage( MSIPACKAGE *, LPCWSTR, LPCWSTR );
|
||||
|
@ -414,6 +416,7 @@ extern void msi_dialog_destroy( msi_dialog* );
|
|||
extern BOOL msi_dialog_register_class( void );
|
||||
extern void msi_dialog_unregister_class( void );
|
||||
extern void msi_dialog_handle_event( msi_dialog*, LPCWSTR, LPCWSTR, MSIRECORD * );
|
||||
extern UINT msi_dialog_reset( msi_dialog *dialog );
|
||||
|
||||
/* preview */
|
||||
extern MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE * );
|
||||
|
|
|
@ -639,9 +639,15 @@ MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR szColumnNameBuffer,
|
|||
return r;
|
||||
}
|
||||
|
||||
MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
|
||||
{
|
||||
FIXME("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_GUID( CLSID_MsiTransform, 0x000c1082, 0x0000, 0x0000, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
|
||||
|
||||
static UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
|
||||
UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
|
||||
LPCWSTR szTransformFile, int iErrorCond )
|
||||
{
|
||||
UINT r;
|
||||
|
|
|
@ -228,6 +228,8 @@ static VOID set_installer_properties(MSIPACKAGE *package)
|
|||
static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0};
|
||||
static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};
|
||||
static const WCHAR szScreenFormat[] = {'%','d',0};
|
||||
static const WCHAR szIntel[] = { 'I','n','t','e','l',0 };
|
||||
SYSTEM_INFO sys_info;
|
||||
|
||||
/*
|
||||
* Other things that probably should be set:
|
||||
|
@ -353,6 +355,13 @@ static VOID set_installer_properties(MSIPACKAGE *package)
|
|||
sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);
|
||||
MSI_SetPropertyW( package, szVersionMsi, bufstr );
|
||||
|
||||
GetSystemInfo( &sys_info );
|
||||
if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
|
||||
{
|
||||
sprintfW( bufstr, szScreenFormat, sys_info.wProcessorLevel );
|
||||
MSI_SetPropertyW( package, szIntel, bufstr );
|
||||
}
|
||||
|
||||
/* Screen properties. */
|
||||
dc = GetDC(0);
|
||||
sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, HORZRES ) );
|
||||
|
|
Loading…
Reference in a new issue