Skip to content
Snippets Groups Projects
Commit af3ae0c4 authored by Andrew Eikum's avatar Andrew Eikum Committed by Alexandre Julliard
Browse files

oleaut32: Implement ICreateTypeLib::SaveAllChanges.

parent 97f9d6fd
No related branches found
No related tags found
No related merge requests found
......@@ -8579,11 +8579,1258 @@ static HRESULT WINAPI ICreateTypeLib2_fnSetLibFlags(ICreateTypeLib2 *iface,
return S_OK;
}
typedef struct tagWMSFT_SegContents {
DWORD len;
void *data;
} WMSFT_SegContents;
typedef struct tagWMSFT_TLBFile {
MSFT_Header header;
WMSFT_SegContents typeinfo_seg;
WMSFT_SegContents impfile_seg;
WMSFT_SegContents impinfo_seg;
WMSFT_SegContents ref_seg;
WMSFT_SegContents lib_seg;
WMSFT_SegContents guid_seg;
WMSFT_SegContents res07_seg;
WMSFT_SegContents name_seg;
WMSFT_SegContents string_seg;
WMSFT_SegContents typdesc_seg;
WMSFT_SegContents arraydesc_seg;
WMSFT_SegContents custdata_seg;
WMSFT_SegContents cdguids_seg;
MSFT_SegDir segdir;
WMSFT_SegContents aux_seg;
} WMSFT_TLBFile;
static HRESULT WMSFT_compile_strings(ITypeLibImpl *This,
WMSFT_TLBFile *file)
{
TLBString *str;
UINT last_offs;
char *data;
file->string_seg.len = 0;
LIST_FOR_EACH_ENTRY(str, &This->string_list, TLBString, entry) {
int size;
size = WideCharToMultiByte(CP_ACP, 0, str->str, strlenW(str->str), NULL, 0, NULL, NULL);
if (size == 0)
return E_UNEXPECTED;
size += sizeof(INT16);
if (size % 4)
size = (size + 4) & ~0x3;
if (size < 8)
size = 8;
file->string_seg.len += size;
/* temporarily use str->offset to store the length of the aligned,
* converted string */
str->offset = size;
}
file->string_seg.data = data = heap_alloc(file->string_seg.len);
last_offs = 0;
LIST_FOR_EACH_ENTRY(str, &This->string_list, TLBString, entry) {
int size;
size = WideCharToMultiByte(CP_ACP, 0, str->str, strlenW(str->str),
data + sizeof(INT16), file->string_seg.len - last_offs - sizeof(INT16), NULL, NULL);
if (size == 0) {
heap_free(file->string_seg.data);
return E_UNEXPECTED;
}
*((INT16*)data) = size;
memset(data + sizeof(INT16) + size, 0x57, str->offset - size - sizeof(INT16));
size = str->offset;
data += size;
str->offset = last_offs;
last_offs += size;
}
return S_OK;
}
static HRESULT WMSFT_compile_names(ITypeLibImpl *This,
WMSFT_TLBFile *file)
{
TLBString *str;
UINT last_offs;
char *data;
MSFT_NameIntro *last_intro = NULL;
file->header.nametablecount = 0;
file->header.nametablechars = 0;
file->name_seg.len = 0;
LIST_FOR_EACH_ENTRY(str, &This->name_list, TLBString, entry) {
int size;
size = strlenW(str->str);
file->header.nametablechars += size;
file->header.nametablecount++;
size = WideCharToMultiByte(CP_ACP, 0, str->str, size, NULL, 0, NULL, NULL);
if (size == 0)
return E_UNEXPECTED;
size += sizeof(MSFT_NameIntro);
if (size % 4)
size = (size + 4) & ~0x3;
if (size < 8)
size = 8;
file->name_seg.len += size;
/* temporarily use str->offset to store the length of the aligned,
* converted string */
str->offset = size;
}
file->name_seg.data = data = heap_alloc(file->name_seg.len);
last_offs = 0;
LIST_FOR_EACH_ENTRY(str, &This->name_list, TLBString, entry) {
int size;
MSFT_NameIntro *intro = (MSFT_NameIntro*)data;
size = WideCharToMultiByte(CP_ACP, 0, str->str, strlenW(str->str),
data + sizeof(MSFT_NameIntro),
file->name_seg.len - last_offs - sizeof(MSFT_NameIntro), NULL, NULL);
if (size == 0) {
heap_free(file->name_seg.data);
return E_UNEXPECTED;
}
data[sizeof(MSFT_NameIntro) + size] = '\0';
intro->hreftype = -1; /* TODO? */
intro->next_hash = -1;
intro->namelen = size & 0xFF;
/* TODO: namelen & 0xFF00 == ??? maybe HREF type indicator? */
intro->namelen |= LHashValOfNameSysA(This->syskind,
This->lcid, data + sizeof(MSFT_NameIntro)) << 16;
memset(data + sizeof(MSFT_NameIntro) + size, 0x57,
str->offset - size - sizeof(MSFT_NameIntro));
/* update str->offset to actual value to use in other
* compilation functions that require positions within
* the string table */
last_intro = intro;
size = str->offset;
data += size;
str->offset = last_offs;
last_offs += size;
}
if(last_intro)
last_intro->hreftype = 0; /* last one is 0? */
return S_OK;
}
static HRESULT WMSFT_compile_guids(ITypeLibImpl *This, WMSFT_TLBFile *file)
{
TLBGuid *guid;
MSFT_GuidEntry *entry;
DWORD offs;
file->guid_seg.len = sizeof(MSFT_GuidEntry) * list_count(&This->guid_list);
file->guid_seg.data = heap_alloc(file->guid_seg.len);
entry = file->guid_seg.data;
offs = 0;
LIST_FOR_EACH_ENTRY(guid, &This->guid_list, TLBGuid, entry){
memcpy(&entry->guid, &guid->guid, sizeof(GUID));
entry->hreftype = 0xFFFFFFFF; /* TODO */
entry->next_hash = 0xFFFFFFFF; /* TODO? */
guid->offset = offs;
offs += sizeof(MSFT_GuidEntry);
++entry;
}
--entry;
entry->next_hash = 0; /* last one has 0? */
return S_OK;
}
static DWORD WMSFT_encode_variant(VARIANT *value, WMSFT_TLBFile *file)
{
VARIANT v = *value;
VARTYPE arg_type = V_VT(value);
int mask = 0;
HRESULT hres;
DWORD ret = file->custdata_seg.len;
if(arg_type == VT_INT)
arg_type = VT_I4;
if(arg_type == VT_UINT)
arg_type = VT_UI4;
v = *value;
if(V_VT(value) != arg_type) {
hres = VariantChangeType(&v, value, 0, arg_type);
if(FAILED(hres)){
ERR("VariantChangeType failed: %08x\n", hres);
return -1;
}
}
/* Check if default value can be stored in-place */
switch(arg_type){
case VT_I4:
case VT_UI4:
mask = 0x3ffffff;
if(V_UI4(&v) > 0x3ffffff)
break;
/* fall through */
case VT_I1:
case VT_UI1:
case VT_BOOL:
if(!mask)
mask = 0xff;
/* fall through */
case VT_I2:
case VT_UI2:
if(!mask)
mask = 0xffff;
return ((0x80 + 0x4 * V_VT(value)) << 24) | (V_UI4(&v) & mask);
}
/* have to allocate space in custdata_seg */
switch(arg_type) {
case VT_I4:
case VT_R4:
case VT_UI4:
case VT_INT:
case VT_UINT:
case VT_HRESULT:
case VT_PTR: {
/* Construct the data to be allocated */
int *data;
if(file->custdata_seg.data){
file->custdata_seg.data = heap_realloc(file->custdata_seg.data, file->custdata_seg.len + sizeof(int) * 2);
data = (int *)(((char *)file->custdata_seg.data) + file->custdata_seg.len);
file->custdata_seg.len += sizeof(int) * 2;
}else{
file->custdata_seg.len = sizeof(int) * 2;
data = file->custdata_seg.data = heap_alloc(file->custdata_seg.len);
}
data[0] = V_VT(value) + (V_UI4(&v) << 16);
data[1] = (V_UI4(&v) >> 16) + 0x57570000;
/* TODO: Check if the encoded data is already present in custdata_seg */
return ret;
}
case VT_BSTR: {
int i, len = (6+SysStringLen(V_BSTR(&v))+3) & ~0x3;
char *data;
if(file->custdata_seg.data){
file->custdata_seg.data = heap_realloc(file->custdata_seg.data, file->custdata_seg.len + len);
data = ((char *)file->custdata_seg.data) + file->custdata_seg.len;
file->custdata_seg.len += len;
}else{
file->custdata_seg.len = len;
data = file->custdata_seg.data = heap_alloc(file->custdata_seg.len);
}
*((unsigned short *)data) = V_VT(value);
*((unsigned int *)(data+2)) = SysStringLen(V_BSTR(&v));
for(i=0; i<SysStringLen(V_BSTR(&v)); i++) {
if(V_BSTR(&v)[i] <= 0x7f)
data[i+6] = V_BSTR(&v)[i];
else
data[i+6] = '?';
}
WideCharToMultiByte(CP_ACP, 0, V_BSTR(&v), SysStringLen(V_BSTR(&v)), &data[6], len-6, NULL, NULL);
for(i=6+SysStringLen(V_BSTR(&v)); i<len; i++)
data[i] = 0x57;
/* TODO: Check if the encoded data is already present in custdata_seg */
return ret;
}
default:
FIXME("Argument type not yet handled\n");
return -1;
}
}
static DWORD WMSFT_append_typedesc(TYPEDESC *desc, WMSFT_TLBFile *file, DWORD *out_mix, INT16 *out_size);
static DWORD WMSFT_append_arraydesc(ARRAYDESC *desc, WMSFT_TLBFile *file)
{
DWORD offs = file->arraydesc_seg.len;
DWORD *encoded;
USHORT i;
/* TODO: we should check for duplicates, but that's harder because each
* chunk is variable length (really we should store TYPEDESC and ARRAYDESC
* at the library-level) */
file->arraydesc_seg.len += (2 + desc->cDims * 2) * sizeof(DWORD);
if(!file->arraydesc_seg.data)
file->arraydesc_seg.data = heap_alloc(file->arraydesc_seg.len);
else
file->arraydesc_seg.data = heap_realloc(file->arraydesc_seg.data, file->arraydesc_seg.len);
encoded = (DWORD*)((char *)file->arraydesc_seg.data) + offs;
encoded[0] = WMSFT_append_typedesc(&desc->tdescElem, file, NULL, NULL);
encoded[1] = desc->cDims | ((desc->cDims * 2 * sizeof(DWORD)) << 16);
for(i = 0; i < desc->cDims; ++i){
encoded[2 + i * 2] = desc->rgbounds[i].cElements;
encoded[2 + i * 2 + 1] = desc->rgbounds[i].lLbound;
}
return offs;
}
static DWORD WMSFT_append_typedesc(TYPEDESC *desc, WMSFT_TLBFile *file, DWORD *out_mix, INT16 *out_size)
{
DWORD junk;
INT16 junk2;
DWORD offs = 0;
DWORD encoded[2];
VARTYPE vt = desc->vt & VT_TYPEMASK, subtype;
char *data;
if(!out_mix)
out_mix = &junk;
if(!out_size)
out_size = &junk2;
switch(vt){
case VT_INT:
subtype = VT_I4;
break;
case VT_UINT:
subtype = VT_UI4;
break;
case VT_VOID:
subtype = VT_EMPTY;
break;
default:
subtype = vt;
break;
}
switch(vt){
case VT_INT:
case VT_UINT:
case VT_I1:
case VT_UI1:
case VT_I2:
case VT_UI2:
case VT_I4:
case VT_UI4:
case VT_BOOL:
case VT_R4:
case VT_ERROR:
case VT_BSTR:
case VT_HRESULT:
case VT_CY:
case VT_VOID:
case VT_VARIANT:
*out_mix = subtype;
return 0x80000000 | (subtype << 16) | desc->vt;
}
if(vt == VT_PTR || vt == VT_SAFEARRAY){
DWORD mix;
encoded[1] = WMSFT_append_typedesc(desc->u.lptdesc, file, &mix, out_size);
encoded[0] = desc->vt | ((mix | VT_BYREF) << 16);
*out_mix = 0x7FFF;
*out_size += 2 * sizeof(DWORD);
}else if(vt == VT_CARRAY){
encoded[0] = desc->vt | (0x7FFE << 16);
encoded[1] = WMSFT_append_arraydesc(desc->u.lpadesc, file);
*out_mix = 0x7FFE;
}else if(vt == VT_USERDEFINED){
encoded[0] = desc->vt | (0x7FFF << 16);
encoded[1] = desc->u.hreftype;
*out_mix = 0x7FFF; /* FIXME: Should get TYPEKIND of the hreftype, e.g. TKIND_ENUM => VT_I4 */
}else{
FIXME("Don't know what to do! VT: 0x%x\n", desc->vt);
*out_mix = desc->vt;
return 0x80000000 | (desc->vt << 16) | desc->vt;
}
data = file->typdesc_seg.data;
while(offs < file->typdesc_seg.len){
if(!memcmp(&data[offs], encoded, sizeof(encoded)))
return offs;
offs += sizeof(encoded);
}
file->typdesc_seg.len += sizeof(encoded);
if(!file->typdesc_seg.data)
data = file->typdesc_seg.data = heap_alloc(file->typdesc_seg.len);
else
data = file->typdesc_seg.data = heap_realloc(file->typdesc_seg.data, file->typdesc_seg.len);
memcpy(&data[offs], encoded, sizeof(encoded));
return offs;
}
static DWORD WMSFT_compile_custdata(struct list *custdata_list, WMSFT_TLBFile *file)
{
WMSFT_SegContents *cdguids_seg = &file->cdguids_seg;
DWORD ret = cdguids_seg->len, offs;
MSFT_CDGuid *cdguid = cdguids_seg->data;
TLBCustData *cd;
if(list_empty(custdata_list))
return -1;
cdguids_seg->len += sizeof(MSFT_CDGuid) * list_count(custdata_list);
if(!cdguids_seg->data){
cdguid = cdguids_seg->data = heap_alloc(cdguids_seg->len);
}else
cdguids_seg->data = heap_realloc(cdguids_seg->data, cdguids_seg->len);
offs = ret + sizeof(MSFT_CDGuid);
LIST_FOR_EACH_ENTRY(cd, custdata_list, TLBCustData, entry){
cdguid->GuidOffset = cd->guid->offset;
cdguid->DataOffset = WMSFT_encode_variant(&cd->data, file);
cdguid->next = offs;
offs += sizeof(MSFT_CDGuid);
++cdguid;
}
--cdguid;
cdguid->next = -1;
return ret;
}
static DWORD WMSFT_compile_typeinfo_aux(ITypeInfoImpl *info,
WMSFT_TLBFile *file)
{
WMSFT_SegContents *aux_seg = &file->aux_seg;
DWORD ret = aux_seg->len, i, j, recorded_size = 0, extra_size = 0;
MSFT_VarRecord *varrecord;
MSFT_FuncRecord *funcrecord;
MEMBERID *memid;
DWORD *name, *offsets, offs;
for(i = 0; i < info->cFuncs; ++i){
TLBFuncDesc *desc = &info->funcdescs[i];
recorded_size += 6 * sizeof(INT); /* mandatory fields */
/* optional fields */
/* TODO: oArgCustData - FuncSetCustData not impl yet */
if(!list_empty(&desc->custdata_list))
recorded_size += 7 * sizeof(INT);
else if(desc->HelpStringContext != 0)
recorded_size += 6 * sizeof(INT);
/* res9? resA? */
else if(desc->Entry)
recorded_size += 3 * sizeof(INT);
else if(desc->HelpString)
recorded_size += 2 * sizeof(INT);
else if(desc->helpcontext)
recorded_size += sizeof(INT);
recorded_size += desc->funcdesc.cParams * sizeof(MSFT_ParameterInfo);
for(j = 0; j < desc->funcdesc.cParams; ++j){
if(desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT){
recorded_size += desc->funcdesc.cParams * sizeof(INT);
break;
}
}
extra_size += 2 * sizeof(INT); /* memberid, name offs */
}
for(i = 0; i < info->cVars; ++i){
TLBVarDesc *desc = &info->vardescs[i];
recorded_size += 5 * sizeof(INT); /* mandatory fields */
/* optional fields */
if(desc->HelpStringContext != 0)
recorded_size += 5 * sizeof(INT);
else if(!list_empty(&desc->custdata_list))
recorded_size += 4 * sizeof(INT);
/* res9? */
else if(desc->HelpString)
recorded_size += 2 * sizeof(INT);
else if(desc->HelpContext != 0)
recorded_size += sizeof(INT);
extra_size += 2 * sizeof(INT); /* memberid, name offs */
}
if(!recorded_size && !extra_size)
return ret;
extra_size += sizeof(INT); /* total aux size for this typeinfo */
aux_seg->len += recorded_size + extra_size;
aux_seg->len += sizeof(INT) * (info->cVars + info->cFuncs); /* offsets at the end */
if(aux_seg->data)
aux_seg->data = heap_realloc(aux_seg->data, aux_seg->len);
else
aux_seg->data = heap_alloc(aux_seg->len);
*((DWORD*)((char *)aux_seg->data + ret)) = recorded_size;
offsets = (DWORD*)((char *)aux_seg->data + ret + recorded_size + extra_size);
offs = 0;
funcrecord = (MSFT_FuncRecord*)(((char *)aux_seg->data) + ret + sizeof(INT));
for(i = 0; i < info->cFuncs; ++i){
TLBFuncDesc *desc = &info->funcdescs[i];
DWORD size = 6 * sizeof(INT), paramdefault_size = 0, *paramdefault;
funcrecord->funcdescsize = sizeof(desc->funcdesc) + desc->funcdesc.cParams * sizeof(ELEMDESC);
funcrecord->DataType = WMSFT_append_typedesc(&desc->funcdesc.elemdescFunc.tdesc, file, NULL, &funcrecord->funcdescsize);
funcrecord->Flags = desc->funcdesc.wFuncFlags;
funcrecord->VtableOffset = desc->funcdesc.oVft;
/* FKCCIC:
* XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX
* ^^^funckind
* ^^^ ^invkind
* ^has_cust_data
* ^^^^callconv
* ^has_param_defaults
* ^oEntry_is_intresource
*/
funcrecord->FKCCIC =
desc->funcdesc.funckind |
(desc->funcdesc.invkind << 3) |
(list_empty(&desc->custdata_list) ? 0 : 0x80) |
(desc->funcdesc.callconv << 8);
if(desc->Entry && desc->Entry != (TLBString*)-1 && IS_INTRESOURCE(desc->Entry))
funcrecord->FKCCIC |= 0x2000;
for(j = 0; j < desc->funcdesc.cParams; ++j){
if(desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT){
paramdefault_size = sizeof(INT) * desc->funcdesc.cParams;
funcrecord->funcdescsize += sizeof(PARAMDESCEX);
}
}
if(paramdefault_size > 0)
funcrecord->FKCCIC |= 0x1000;
funcrecord->nrargs = desc->funcdesc.cParams;
funcrecord->nroargs = desc->funcdesc.cParamsOpt;
/* optional fields */
/* res9? resA? */
if(!list_empty(&desc->custdata_list)){
size += 7 * sizeof(INT);
funcrecord->HelpContext = desc->helpcontext;
if(desc->HelpString)
funcrecord->oHelpString = desc->HelpString->offset;
else
funcrecord->oHelpString = -1;
if(!desc->Entry)
funcrecord->oEntry = -1;
else if(IS_INTRESOURCE(desc->Entry))
funcrecord->oEntry = LOWORD(desc->Entry);
else
funcrecord->oEntry = desc->Entry->offset;
funcrecord->res9 = -1;
funcrecord->resA = -1;
funcrecord->HelpStringContext = desc->HelpStringContext;
funcrecord->oCustData = WMSFT_compile_custdata(&desc->custdata_list, file);
}else if(desc->HelpStringContext != 0){
size += 6 * sizeof(INT);
funcrecord->HelpContext = desc->helpcontext;
if(desc->HelpString)
funcrecord->oHelpString = desc->HelpString->offset;
else
funcrecord->oHelpString = -1;
if(!desc->Entry)
funcrecord->oEntry = -1;
else if(IS_INTRESOURCE(desc->Entry))
funcrecord->oEntry = LOWORD(desc->Entry);
else
funcrecord->oEntry = desc->Entry->offset;
funcrecord->res9 = -1;
funcrecord->resA = -1;
funcrecord->HelpStringContext = desc->HelpStringContext;
}else if(desc->Entry){
size += 3 * sizeof(INT);
funcrecord->HelpContext = desc->helpcontext;
if(desc->HelpString)
funcrecord->oHelpString = desc->HelpString->offset;
else
funcrecord->oHelpString = -1;
if(!desc->Entry)
funcrecord->oEntry = -1;
else if(IS_INTRESOURCE(desc->Entry))
funcrecord->oEntry = LOWORD(desc->Entry);
else
funcrecord->oEntry = desc->Entry->offset;
}else if(desc->HelpString){
size += 2 * sizeof(INT);
funcrecord->HelpContext = desc->helpcontext;
funcrecord->oHelpString = desc->HelpString->offset;
}else if(desc->helpcontext){
size += sizeof(INT);
funcrecord->HelpContext = desc->helpcontext;
}
paramdefault = (DWORD*)((char *)funcrecord + size);
size += paramdefault_size;
for(j = 0; j < desc->funcdesc.cParams; ++j){
MSFT_ParameterInfo *info = (MSFT_ParameterInfo*)(((char *)funcrecord) + size);
info->DataType = WMSFT_append_typedesc(&desc->funcdesc.lprgelemdescParam[j].tdesc, file, NULL, &funcrecord->funcdescsize);
if(desc->pParamDesc[j].Name)
info->oName = desc->pParamDesc[j].Name->offset;
else
info->oName = -1;
info->Flags = desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags;
if(paramdefault_size){
if(desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
*paramdefault = WMSFT_encode_variant(&desc->funcdesc.lprgelemdescParam[j].u.paramdesc.pparamdescex->varDefaultValue, file);
else if(paramdefault_size)
*paramdefault = -1;
++paramdefault;
}
size += sizeof(MSFT_ParameterInfo);
}
funcrecord->Info = size | (i << 16); /* is it just the index? */
*offsets = offs;
offs += size;
++offsets;
funcrecord = (MSFT_FuncRecord*)(((char*)funcrecord) + size);
}
varrecord = (MSFT_VarRecord*)funcrecord;
for(i = 0; i < info->cVars; ++i){
TLBVarDesc *desc = &info->vardescs[i];
DWORD size = 5 * sizeof(INT);
varrecord->vardescsize = sizeof(desc->vardesc);
varrecord->DataType = WMSFT_append_typedesc(&desc->vardesc.elemdescVar.tdesc, file, NULL, &varrecord->vardescsize);
varrecord->Flags = desc->vardesc.wVarFlags;
varrecord->VarKind = desc->vardesc.varkind;
if(desc->vardesc.varkind == VAR_CONST){
varrecord->vardescsize += sizeof(VARIANT);
varrecord->OffsValue = WMSFT_encode_variant(desc->vardesc.u.lpvarValue, file);
}else
varrecord->OffsValue = desc->vardesc.u.oInst;
/* res9? */
if(desc->HelpStringContext != 0){
size += 5 * sizeof(INT);
varrecord->HelpContext = desc->HelpContext;
if(desc->HelpString)
varrecord->HelpString = desc->HelpString->offset;
else
varrecord->HelpString = -1;
varrecord->res9 = -1;
varrecord->oCustData = WMSFT_compile_custdata(&desc->custdata_list, file);
varrecord->HelpStringContext = desc->HelpStringContext;
}else if(!list_empty(&desc->custdata_list)){
size += 4 * sizeof(INT);
varrecord->HelpContext = desc->HelpContext;
if(desc->HelpString)
varrecord->HelpString = desc->HelpString->offset;
else
varrecord->HelpString = -1;
varrecord->res9 = -1;
varrecord->oCustData = WMSFT_compile_custdata(&desc->custdata_list, file);
}else if(desc->HelpString){
size += 2 * sizeof(INT);
varrecord->HelpContext = desc->HelpContext;
if(desc->HelpString)
varrecord->HelpString = desc->HelpString->offset;
else
varrecord->HelpString = -1;
}else if(desc->HelpContext != 0){
size += sizeof(INT);
varrecord->HelpContext = desc->HelpContext;
}
varrecord->Info = size | (i << 16);
*offsets = offs;
offs += size;
++offsets;
varrecord = (MSFT_VarRecord*)(((char*)varrecord) + size);
}
memid = (MEMBERID*)varrecord;
for(i = 0; i < info->cFuncs; ++i){
TLBFuncDesc *desc = &info->funcdescs[i];
*memid = desc->funcdesc.memid;
++memid;
}
for(i = 0; i < info->cVars; ++i){
TLBVarDesc *desc = &info->vardescs[i];
*memid = desc->vardesc.memid;
++memid;
}
name = (UINT*)memid;
for(i = 0; i < info->cFuncs; ++i){
TLBFuncDesc *desc = &info->funcdescs[i];
if(desc->Name)
*name = desc->Name->offset;
else
*name = -1;
++name;
}
for(i = 0; i < info->cVars; ++i){
TLBVarDesc *desc = &info->vardescs[i];
if(desc->Name)
*name = desc->Name->offset;
else
*name = -1;
++name;
}
return ret;
}
typedef struct tagWMSFT_RefChunk {
DWORD href;
DWORD res04;
DWORD res08;
DWORD next;
} WMSFT_RefChunk;
static DWORD WMSFT_compile_typeinfo_ref(ITypeInfoImpl *info, WMSFT_TLBFile *file)
{
DWORD offs = file->ref_seg.len, i;
WMSFT_RefChunk *chunk;
file->ref_seg.len += info->cImplTypes * sizeof(WMSFT_RefChunk);
if(!file->ref_seg.data)
file->ref_seg.data = heap_alloc(file->ref_seg.len);
else
file->ref_seg.data = heap_realloc(file->ref_seg.data, file->ref_seg.len);
chunk = (WMSFT_RefChunk*)((char*)file->ref_seg.data + offs);
for(i = 0; i < info->cImplTypes; ++i){
chunk->href = info->impltypes[i].hRef;
chunk->res04 = info->impltypes[i].implflags;
chunk->res08 = -1;
if(i < info->cImplTypes - 1)
chunk->next = offs + sizeof(WMSFT_RefChunk) * (i + 1);
else
chunk->next = -1;
++chunk;
}
return offs;
}
static DWORD WMSFT_compile_typeinfo(ITypeInfoImpl *info, INT16 index, WMSFT_TLBFile *file, char *data)
{
DWORD size;
size = sizeof(MSFT_TypeInfoBase);
if(data){
MSFT_TypeInfoBase *base = (void*)data;
if(info->wTypeFlags & TYPEFLAG_FDUAL)
base->typekind = TKIND_DISPATCH;
else
base->typekind = info->typekind;
base->typekind |= index << 16; /* TODO: There are some other flags here */
base->typekind |= (info->cbAlignment << 11) | (info->cbAlignment << 6);
base->memoffset = WMSFT_compile_typeinfo_aux(info, file);
base->res2 = 0;
base->res3 = 0;
base->res4 = 3;
base->res5 = 0;
base->cElement = (info->cVars << 16) | info->cFuncs;
base->res7 = 0;
base->res8 = 0;
base->res9 = 0;
base->resA = 0;
if(info->guid)
base->posguid = info->guid->offset;
else
base->posguid = -1;
base->flags = info->wTypeFlags;
if(info->Name)
base->NameOffset = info->Name->offset;
else
base->NameOffset = -1;
base->version = (info->wMinorVerNum << 16) | info->wMajorVerNum;
if(info->DocString)
base->docstringoffs = info->DocString->offset;
else
base->docstringoffs = -1;
base->helpstringcontext = info->dwHelpStringContext;
base->helpcontext = info->dwHelpContext;
base->oCustData = WMSFT_compile_custdata(&info->custdata_list, file);
base->cImplTypes = info->cImplTypes;
base->cbSizeVft = info->cbSizeVft;
base->size = info->cbSizeInstance;
if(info->typekind == TKIND_COCLASS){
base->datatype1 = WMSFT_compile_typeinfo_ref(info, file);
}else if(info->typekind == TKIND_ALIAS){
base->datatype1 = WMSFT_append_typedesc(&info->tdescAlias, file, NULL, NULL);
}else if(info->typekind == TKIND_MODULE){
if(info->DllName)
base->datatype1 = info->DllName->offset;
else
base->datatype1 = -1;
}else{
if(info->cImplTypes > 0)
base->datatype1 = info->impltypes[0].hRef;
else
base->datatype1 = -1;
}
base->datatype2 = index; /* FIXME: i think there's more here */
base->res18 = 0;
base->res19 = -1;
}
return size;
}
static void WMSFT_compile_typeinfo_seg(ITypeLibImpl *This, WMSFT_TLBFile *file, DWORD *junk)
{
UINT i;
file->typeinfo_seg.len = 0;
for(i = 0; i < This->TypeInfoCount; ++i){
ITypeInfoImpl *info = This->typeinfos[i];
*junk = file->typeinfo_seg.len;
++junk;
file->typeinfo_seg.len += WMSFT_compile_typeinfo(info, i, NULL, NULL);
}
file->typeinfo_seg.data = heap_alloc(file->typeinfo_seg.len);
memset(file->typeinfo_seg.data, 0x96, file->typeinfo_seg.len);
file->aux_seg.len = 0;
file->aux_seg.data = NULL;
file->typeinfo_seg.len = 0;
for(i = 0; i < This->TypeInfoCount; ++i){
ITypeInfoImpl *info = This->typeinfos[i];
file->typeinfo_seg.len += WMSFT_compile_typeinfo(info, i, file,
((char *)file->typeinfo_seg.data) + file->typeinfo_seg.len);
}
}
typedef struct tagWMSFT_ImpFile {
INT guid_offs;
LCID lcid;
DWORD version;
} WMSFT_ImpFile;
static void WMSFT_compile_impfile(ITypeLibImpl *This, WMSFT_TLBFile *file)
{
TLBImpLib *implib;
WMSFT_ImpFile *impfile;
char *data;
DWORD last_offs = 0;
file->impfile_seg.len = 0;
LIST_FOR_EACH_ENTRY(implib, &This->implib_list, TLBImpLib, entry){
int size = 0;
if(implib->name){
WCHAR *path = strrchrW(implib->name, '\\');
if(path)
++path;
else
path = implib->name;
size = WideCharToMultiByte(CP_ACP, 0, path, strlenW(path), NULL, 0, NULL, NULL);
if (size == 0)
ERR("failed to convert wide string: %s\n", debugstr_w(path));
}
size += sizeof(INT16);
if (size % 4)
size = (size + 4) & ~0x3;
if (size < 8)
size = 8;
file->impfile_seg.len += sizeof(WMSFT_ImpFile) + size;
}
data = file->impfile_seg.data = heap_alloc(file->impfile_seg.len);
LIST_FOR_EACH_ENTRY(implib, &This->implib_list, TLBImpLib, entry){
int strlen = 0, size;
impfile = (WMSFT_ImpFile*)data;
impfile->guid_offs = implib->guid->offset;
impfile->lcid = implib->lcid;
impfile->version = (implib->wVersionMinor << 16) | implib->wVersionMajor;
data += sizeof(WMSFT_ImpFile);
if(implib->name){
WCHAR *path= strrchrW(implib->name, '\\');
if(path)
++path;
else
path = implib->name;
strlen = WideCharToMultiByte(CP_ACP, 0, path, strlenW(path),
data + sizeof(INT16), file->impfile_seg.len - last_offs - sizeof(INT16), NULL, NULL);
if (strlen == 0)
ERR("failed to convert wide string: %s\n", debugstr_w(path));
}
*((INT16*)data) = (strlen << 2) | 1; /* FIXME: is that a flag, or what? */
size = strlen + sizeof(INT16);
if (size % 4)
size = (size + 4) & ~0x3;
if (size < 8)
size = 8;
memset(data + sizeof(INT16) + strlen, 0x57, size - strlen - sizeof(INT16));
data += size;
implib->offset = last_offs;
last_offs += size + sizeof(WMSFT_ImpFile);
}
}
static void WMSFT_compile_impinfo(ITypeLibImpl *This, WMSFT_TLBFile *file)
{
MSFT_ImpInfo *info;
TLBRefType *ref_type;
UINT i = 0;
WMSFT_compile_impfile(This, file);
file->impinfo_seg.len = sizeof(MSFT_ImpInfo) * list_count(&This->ref_list);
info = file->impinfo_seg.data = heap_alloc(file->impinfo_seg.len);
LIST_FOR_EACH_ENTRY(ref_type, &This->ref_list, TLBRefType, entry){
info->flags = i | ((ref_type->tkind & 0xFF) << 24);
if(ref_type->index == TLB_REF_USE_GUID){
info->flags |= MSFT_IMPINFO_OFFSET_IS_GUID;
info->oGuid = ref_type->guid->offset;
}else
info->oGuid = ref_type->index;
info->oImpFile = ref_type->pImpTLInfo->offset;
++i;
++info;
}
}
static void WMSFT_compile_lib(ITypeLibImpl *This, WMSFT_TLBFile *file)
{
/* TODO: What actually goes here? */
file->lib_seg.len = 0x80;
file->lib_seg.data = heap_alloc(file->lib_seg.len);
memset(file->lib_seg.data, 0xFF, file->lib_seg.len);
#if 0
/* sometimes, first element is offset to last guid, for some reason */
if(This->guid)
*(DWORD*)file->lib_seg.data =
(list_count(&This->guid_list) - 1) * sizeof(MSFT_GuidEntry);
#endif
}
static void WMSFT_compile_res07(ITypeLibImpl *This, WMSFT_TLBFile *file)
{
/* TODO: What actually goes here?
* Wild speculation:
* It's something to do with the Name table (and string table?). When you
* add a new name, the offset to that name from within the Name table gets
* stuck somewhere in res07, apparently starting at the end of the segment
* then moving backwards at a rate of 3 bytes per char in the Name. */
file->res07_seg.len = 0x200;
file->res07_seg.data = heap_alloc(file->res07_seg.len);
memset(file->res07_seg.data, 0xFF, file->res07_seg.len);
}
static void tmp_fill_segdir_seg(MSFT_pSeg *segdir, WMSFT_SegContents *contents, DWORD *running_offset)
{
if(contents && contents->len){
segdir->offset = *running_offset;
segdir->length = contents->len;
*running_offset += segdir->length;
}else{
segdir->offset = -1;
segdir->length = 0;
}
/* TODO: do these ever change? */
segdir->res08 = -1;
segdir->res0c = 0xf;
}
static void WMSFT_write_segment(HANDLE outfile, WMSFT_SegContents *segment)
{
DWORD written;
if(segment)
WriteFile(outfile, segment->data, segment->len, &written, NULL);
}
static HRESULT WMSFT_fixup_typeinfos(ITypeLibImpl *This, WMSFT_TLBFile *file,
DWORD file_len)
{
DWORD i;
MSFT_TypeInfoBase *base = (MSFT_TypeInfoBase *)file->typeinfo_seg.data;
for(i = 0; i < This->TypeInfoCount; ++i){
base->memoffset += file_len;
++base;
}
return S_OK;
}
static void WMSFT_free_file(WMSFT_TLBFile *file)
{
HeapFree(GetProcessHeap(), 0, file->typeinfo_seg.data);
HeapFree(GetProcessHeap(), 0, file->lib_seg.data);
HeapFree(GetProcessHeap(), 0, file->guid_seg.data);
HeapFree(GetProcessHeap(), 0, file->ref_seg.data);
HeapFree(GetProcessHeap(), 0, file->impinfo_seg.data);
HeapFree(GetProcessHeap(), 0, file->impfile_seg.data);
HeapFree(GetProcessHeap(), 0, file->res07_seg.data);
HeapFree(GetProcessHeap(), 0, file->name_seg.data);
HeapFree(GetProcessHeap(), 0, file->string_seg.data);
HeapFree(GetProcessHeap(), 0, file->typdesc_seg.data);
HeapFree(GetProcessHeap(), 0, file->arraydesc_seg.data);
HeapFree(GetProcessHeap(), 0, file->custdata_seg.data);
HeapFree(GetProcessHeap(), 0, file->cdguids_seg.data);
HeapFree(GetProcessHeap(), 0, file->aux_seg.data);
}
static HRESULT WINAPI ICreateTypeLib2_fnSaveAllChanges(ICreateTypeLib2 *iface)
{
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
FIXME("%p - stub\n", This);
return E_NOTIMPL;
WMSFT_TLBFile file;
DWORD written, junk_size, junk_offs, running_offset;
BOOL br;
HANDLE outfile;
HRESULT hres;
DWORD *junk;
TRACE("%p\n", This);
memset(&file, 0, sizeof(file));
file.header.magic1 = 0x5446534D;
file.header.magic2 = 0x00010002;
file.header.lcid = This->set_lcid ? This->set_lcid : MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
file.header.lcid2 = This->set_lcid;
file.header.varflags = 0x41; /* TODO?? */
if (This->HelpFile)
file.header.varflags |= 0x10;
if (This->HelpStringDll)
file.header.varflags |= HELPDLLFLAG;
file.header.version = (This->ver_major << 16) | This->ver_minor;
file.header.flags = This->libflags;
file.header.helpstringcontext = 0; /* TODO - SetHelpStringContext not implemented yet */
file.header.helpcontext = This->dwHelpContext;
file.header.res44 = 0x20;
file.header.res48 = 0x80;
file.header.dispatchpos = This->dispatch_href;
/* do name and string compilation to get offsets for other compilations */
hres = WMSFT_compile_names(This, &file);
if (FAILED(hres)){
WMSFT_free_file(&file);
return hres;
}
hres = WMSFT_compile_strings(This, &file);
if (FAILED(hres)){
WMSFT_free_file(&file);
return hres;
}
hres = WMSFT_compile_guids(This, &file);
if (FAILED(hres)){
WMSFT_free_file(&file);
return hres;
}
if(This->HelpFile)
file.header.helpfile = This->HelpFile->offset;
else
file.header.helpfile = -1;
if(This->DocString)
file.header.helpstring = This->DocString->offset;
else
file.header.helpstring = -1;
/* do some more segment compilation */
file.header.nimpinfos = list_count(&This->ref_list);
file.header.nrtypeinfos = This->TypeInfoCount;
if(This->Name)
file.header.NameOffset = This->Name->offset;
else
file.header.NameOffset = -1;
file.header.CustomDataOffset = -1; /* TODO SetCustData not impl yet */
if(This->guid)
file.header.posguid = This->guid->offset;
else
file.header.posguid = -1;
junk_size = file.header.nrtypeinfos * sizeof(DWORD);
if(file.header.varflags & HELPDLLFLAG)
junk_size += sizeof(DWORD);
if(junk_size){
junk = heap_alloc_zero(junk_size);
if(file.header.varflags & HELPDLLFLAG){
*junk = This->HelpStringDll->offset;
junk_offs = 1;
}else
junk_offs = 0;
}else{
junk = NULL;
junk_offs = 0;
}
WMSFT_compile_typeinfo_seg(This, &file, junk + junk_offs);
WMSFT_compile_impinfo(This, &file);
WMSFT_compile_lib(This, &file);
WMSFT_compile_res07(This, &file);
running_offset = 0;
TRACE("header at: 0x%x\n", running_offset);
running_offset += sizeof(file.header);
TRACE("junk at: 0x%x\n", running_offset);
running_offset += junk_size;
TRACE("segdir at: 0x%x\n", running_offset);
running_offset += sizeof(file.segdir);
TRACE("typeinfo at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.pTypeInfoTab, &file.typeinfo_seg, &running_offset);
TRACE("libtab at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.pLibtab, &file.lib_seg, &running_offset);
TRACE("guidtab at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.pGuidTab, &file.guid_seg, &running_offset);
TRACE("reftab at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.pRefTab, &file.ref_seg, &running_offset);
TRACE("impinfo at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.pImpInfo, &file.impinfo_seg, &running_offset);
TRACE("impfiles at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.pImpFiles, &file.impfile_seg, &running_offset);
TRACE("res07 at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.res07, &file.res07_seg, &running_offset);
TRACE("nametab at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.pNametab, &file.name_seg, &running_offset);
TRACE("stringtab at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.pStringtab, &file.string_seg, &running_offset);
TRACE("typdesc at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.pTypdescTab, &file.typdesc_seg, &running_offset);
TRACE("arraydescriptions at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.pArrayDescriptions, &file.arraydesc_seg, &running_offset);
TRACE("custdata at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.pCustData, &file.custdata_seg, &running_offset);
TRACE("cdguids at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.pCDGuids, &file.cdguids_seg, &running_offset);
TRACE("res0e at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.res0e, NULL, &running_offset);
TRACE("res0f at: 0x%x\n", running_offset);
tmp_fill_segdir_seg(&file.segdir.res0f, NULL, &running_offset);
TRACE("aux_seg at: 0x%x\n", running_offset);
WMSFT_fixup_typeinfos(This, &file, running_offset);
outfile = CreateFileW(This->path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0);
if (outfile == INVALID_HANDLE_VALUE){
WMSFT_free_file(&file);
return TYPE_E_IOERROR;
}
br = WriteFile(outfile, &file.header, sizeof(file.header), &written, NULL);
if (!br) {
WMSFT_free_file(&file);
CloseHandle(outfile);
return TYPE_E_IOERROR;
}
br = WriteFile(outfile, junk, junk_size, &written, NULL);
if (!br) {
WMSFT_free_file(&file);
CloseHandle(outfile);
return TYPE_E_IOERROR;
}
br = WriteFile(outfile, &file.segdir, sizeof(file.segdir), &written, NULL);
if (!br) {
WMSFT_free_file(&file);
CloseHandle(outfile);
return TYPE_E_IOERROR;
}
WMSFT_write_segment(outfile, &file.typeinfo_seg);
WMSFT_write_segment(outfile, &file.lib_seg);
WMSFT_write_segment(outfile, &file.guid_seg);
WMSFT_write_segment(outfile, &file.ref_seg);
WMSFT_write_segment(outfile, &file.impinfo_seg);
WMSFT_write_segment(outfile, &file.impfile_seg);
WMSFT_write_segment(outfile, &file.res07_seg);
WMSFT_write_segment(outfile, &file.name_seg);
WMSFT_write_segment(outfile, &file.string_seg);
WMSFT_write_segment(outfile, &file.typdesc_seg);
WMSFT_write_segment(outfile, &file.arraydesc_seg);
WMSFT_write_segment(outfile, &file.custdata_seg);
WMSFT_write_segment(outfile, &file.cdguids_seg);
WMSFT_write_segment(outfile, &file.aux_seg);
WMSFT_free_file(&file);
CloseHandle(outfile);
return S_OK;
}
static HRESULT WINAPI ICreateTypeLib2_fnDeleteTypeInfo(ICreateTypeLib2 *iface,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment