1

总结:我搜索了 MSDN 并想创建自己的SetValue,但我找不到任何源代码。它不在DLL中,就像InitPropVariantFromString在头文件中,但我找不到。:(如果可以的话,请给我看htat C++代码,我会从那里拿走它:)

底部的东西是为了展示我付出的努力。


这是我正在转换的微小 C++ 代码:

OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
 IPropertyStore *pps;
 HRESULT hr = SHGetPropertyStoreForWindow(hwnd, IID_PPV_ARGS(&pps));
 if (SUCCEEDED(hr)) {
  IPropertyStore_SetValue(pps, PKEY_AppUserModel_ID, L"Contoso.Scratch");
 }
}

我已将其翻译为:

  var ppv = ctypes.voidptr_t(0);
  var pps = new IID();
  var HR_pps = CLSIDFromString('{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}', pps.address());
  if (!checkHRESULT(HR_pps)) { throw new Error('checkHRESULT error'); }

  var hr = SHGetPropertyStoreForWindow(hwnd, pps.address(), ppv.address());
  if (!checkHRESULT(hr)) { throw new Error('checkHRESULT error'); }

  var pszValue = ctypes.jschar.array()('Contoso.Scratch'); // PCWSTR
  IPropertyStore_SetValue(pps.address(), PKEY_AppUserModel_ID, pszValue.address());

IPropertyStore_SetValue是我从这个 C++ 转换而来的:

HRESULT IPropertyStore_SetValue(IPropertyStore *pps, REFPROPERTYKEY pkey, PCWSTR pszValue)
{
 PROPVARIANT var;
 HRESULT hr = InitPropVariantFromString(pszValue, &var);
 if (SUCCEEDED(hr)) {
  hr = pps->SetValue(pkey, var);
  PropVariantClear(&var);
 }
 return hr;
}

我得到了它:

var struct_PROPVARIANT = ctypes.StructType('PROPVARIANT', [
  {'fntud': struct_GUID}, // GUID
  {'pid': ctypes.unsigned_long}, // DWORD
  // comment from loomo on union :: union not supported by js-ctypes https://bugzilla.mozilla.org/show_bug.cgi?id=535378 "You can always typecast pointers, at least as long as you know which type is the biggest"
  // so now in my case i know that InitPropVariantFromString is looking to se the pwszVal so forget all the other crap in the union and just leave this one
  {'pwszVal': new ctypes.PointerType(ctypes.jschar)}  // LPWSTR 
]);

var IPropertyStore_SetValue = function(pps /** IPopertyStore pointer **/, pkey /** PROPERTYKEY **/, pszValue /** PCWSTR **/) {
  var v = new struct_PROPVARIANT(); // PROPVARIANT

  var rez = InitPropVariantFromString(pszValue, v.address());
  if (rez) {
    console.info('pps.SetValue', pps.SetValue);
    pps.SetValue(pkey, v);
  } else {
    throw new Error('failed InitPropVariantFromString');
  }
  return true;
}

所以这需要我写InitPropVariantFromString我所做的:

function InitPropVariantFromString(string /** PCWSTR **/, propvarPtr /** PROPVARIANT pointer **/) {
    var hr = SHStrDup(string, propvarPtr.contents.pwszVal.address());
    if (!checkHRESULT(hr)) {
       //PropVariantInit(propvarPtr); //can skip this, it just does a memset
    }
    return true;                      
}

我的 SHSTRDUP 困境中的一个小问题(不是一个问题,只是表明我努力工作,并且通过无法解释的怪异让它发挥作用)

所以这需要我做SHStrDup我认为需要两个参数的,ctypes.jschar.ptr因为它是的第一个参数LPCTSTR 和第二个参数LPTSTR

对于第一个论点,我通过了召回的 PCWSTR ctypes.jschar.array()('Contoso.Scratch')。因此,当我将第一个 arg 定义设置为ctypes.jschar.ptr它不起作用时,它会引发此错误:expected type pointer, got ctypes.jschar.array(16).ptr(ctypes.UInt64("0x2855b560"))

因此,我将定义从定义更改ctypes.jschar.ptr为 定义,ctypes.voidptr_t因此它适用于该参数,但随后在第二个参数上抛出错误,请回忆 propvarPtr.contents.pwszVal.address()

ctypes.jschar.ptr.ptr(ctypes.UInt64("0x20fdb3b4")),

因此,我最终设置了SHStrDupto 的两个参数ctypes.voidptr_t并且它起作用了。不知道为什么,但它奏效了。并且 propvarPtr.contents.pwszVal肯定会被填充,因为当我 console.log 它显示:"propvarPtr.contents.pwszVal" CData { contents: "C" }.

所以最终的SHStrDup定义是这样的:

/* http://msdn.microsoft.com/en-us/library/windows/desktop/bb759924%28v=vs.85%29.aspx
* HRESULT SHStrDup(
*   __in_   LPCTSTR pszSource,
*   __out_  LPTSTR *ppwsz
* );
*/
var SHStrDup = shlwapi.declare('SHStrDupW', ctypes.winapi_abi, ctypes.long, // HRESULT
  ctypes.voidptr_t, // LPCTSTR // should be ctypes.jschar.ptr OR ctypes.char.ptr // im trying to pass PCWSTR here, which is `ctypes.jschar.array()('blah blah').address()`
  ctypes.voidptr_t // LPTSTR // should be ctypes.jschar.ptr OR ctypes.char.ptr // im trying to pass address to struct_PROPVARIANT.pwszVal which is new ctypes.PointerType(ctypes.jschar)
);

所以现在一切都过去了,IPropertyStore_SetValue如果:

  var rez = InitPropVariantFromString(pszValue, v.address());
  if (rez) {
    console.info('pps.SetValue', pps.SetValue);
    pps.SetValue(pkey, v);
  } else {
    throw new Error('failed InitPropVariantFromString');
  }

现在rez是真的,所以它现在会尝试pps.SetValue,这就是它失败的地方,我不知道如何解决它。:(

我搜索了 MSDN 并想创建自己的SetValue,但我找不到任何源代码。它不在DLL中,就像InitPropVariantFromString在头文件中,但我找不到。:(如果可以的话,请给我看htat C++代码,我会从那里拿走它:)

4

1 回答 1

0

解决了,我不得不使用VTBL:https ://github.com/Noitidart/_scratchpad/blob/master/IPropertyStore%20COM%20jsctypes.js

大时代的定义顺序VtblVtbl所以如果你想用s做一些事情,请确保它是正确的

var IPropertyStoreVtbl = new ctypes.StructType('IPropertyStoreVtbl');
var IPropertyStore = new ctypes.StructType('IPropertyStore', [{
    'lpVtbl': IPropertyStoreVtbl.ptr
}]);
this.IPropertyStorePtr = new ctypes.PointerType(IPropertyStore);

IPropertyStoreVtbl.define(
    [{ //start inherit from IUnknown
        'QueryInterface': ctypes.FunctionType(ctypes.stdcall_abi,
            this.HRESULT, [
                IPropertyStore.ptr,
                this.REFIID,    // riid
                this.VOIDPTR    // **ppvObject
            ]).ptr
    }, {
        'AddRef': ctypes.FunctionType(ctypes.stdcall_abi,
            this.ULONG, [
                IPropertyStore.ptr
            ]).ptr
    }, {
        'Release': ctypes.FunctionType(ctypes.stdcall_abi,
            this.ULONG, [
                IPropertyStore.ptr
            ]).ptr
    }, { //end inherit from IUnknown //start IPropertyStore
        'GetCount': ctypes.FunctionType(ctypes.stdcall_abi,
            this.HRESULT, [
                IPropertyStore.ptr,
                this.DWORD.ptr  // *cProps
            ]).ptr
    }, {
        'GetAt': ctypes.FunctionType(ctypes.stdcall_abi,
            this.HRESULT, [
                IPropertyStore.ptr,
                this.DWORD,             // iProp
                this.PROPERTYKEY.ptr    //*pkey
            ]).ptr
    }, {
        'GetValue': ctypes.FunctionType(ctypes.stdcall_abi,
            this.HRESULT, [
                IPropertyStore.ptr,
                this.REFPROPERTYKEY,    // key
                this.PROPVARIANT.ptr    // *pv
            ]).ptr
    }, {
        'SetValue': ctypes.FunctionType(ctypes.stdcall_abi,
            this.HRESULT, [
                IPropertyStore.ptr,
                this.REFPROPERTYKEY,    // key
                this.REFPROPVARIANT     // propvar
            ]).ptr
    }, {
        'Commit': ctypes.FunctionType(ctypes.stdcall_abi,
            this.HRESULT, [
                IPropertyStore.ptr
            ]).ptr
    }]
);

然后得到IPropertyStore一个窗口:

var ppsPtr = new ostypes.IPropertyStorePtr();
var hr_SHGetPropertyStoreForWindow = _dec('SHGetPropertyStoreForWindow')(cHwnd, IID_IPropertyStore.address(), ppsPtr.address()); 
checkHRESULT(hr_SHGetPropertyStoreForWindow, 'SHGetPropertyStoreForWindow');
var pps = ppsPtr.contents.lpVtbl.contents;

现在您可以使用IPropertyStore :: SetValueIPropertyStore :: Release但请确保将ppsPtras 第一个参数传递给它们,然后其余参数就是您所期望的:var hr = pps.SetValue(ppsPtr, firstArgOf_SetValue, secondArgOf_SetValue)


编辑:

从暂存器添加复制粘贴可运行脚本。复制并粘贴: http: //pastebin.mozilla.org/8429999

这将相当于这个 XPCOM:

 var win = Services.wm.getMostRecentWindow(null);
 Cc["@mozilla.org/windows-taskbar;1"].getService(Ci.nsIWinTaskbar).setGroupIdForWindow(win, 'Contoso.Scratch')

是的,它很长,但它的好处是,没有需要设置的 XPCOMRelaunchCommand等等RelaunchIconResource。这就是为什么需要 js-ctypes。

于 2015-01-11T21:19:27.937 回答