2010-06-23 6 views
2

MSI 제품 코드가 주어지면 이미 설치된 제품의 업그레이드 코드 (다른 속성들 중에서)를 얻고 싶습니다. MsiOpenProduct 메서드를 호출하고 MsiGetProductProperty()를 호출하여이 작업을 시도했습니다. (약칭 함) 예는 다음과 같습니다MsiOpenProduct는 설치된 제품에서 속성을 읽는 올바른 방법입니까?

MSIHANDLE handle = NULL; 
MsiOpenProduct(strProductCode,&handle); 
CString strUpgradeCode; 
MsiGetProductProperty(handle,_T("UpgradeCode"), strUpgradeCode.GetBuffer(GUID_LENGTH), &dwSize); 
strUpgradeCode.ReleaseBuffer(); 
MsiCloseHandle(handle); 

이 나에게 원하는 값을 가져오고 MSDN 설명서에서 판단하기는이 할 수있는 유효한 방법처럼 보인다 :

MsiOpenProduct 함수는이 열립니다 제품 데이터베이스에 액세스하는 기능과 함께 사용하는 제품입니다. 핸들이 길어지면 MsiCloseHandle 함수를 핸들과 함께 이라고 호출해야합니다.

그러나 MsiOpenProduct()를 호출하면 "Windows 설치 프로그램이 설치 준비 중입니다 ..."대화 상자가 나타납니다. MsiCloseHandle()을 호출하면 다시 사라집니다.

MsiOpenProduct에 전화를 (무엇을
  • )는 후드 아래에 수행

    궁금 저를 왼쪽? 나는 어떤 행동을 촉발시키고 싶지 않습니다. 단지 속성을 읽고 싶습니다.
  • 이것은 부작용이없는 한 단위 테스트 코드에만 해당되므로 대화 상자가 나타나지 않도록 신경 써야합니다. 이 작업을 수행하는 많은 단위 테스트가 있으므로 신속하게 연속적으로 핸들을 열고 닫을 때 작동해야합니다.
  • MsiGetProductInfo 메서드를 발견했지만 업그레이드 코드를 얻을 수있는 방법이없는 것으로 보입니다. 내가 맞습니까?
  • MsiOpenProduct는 업그레이드 코드와 같은 속성을 읽는 올바른 방법입니까?
+0

같은 결론에 도달했습니다 - 나는 VBScript의 OpenProduct를 사용하여 UpgradeCode (COM 호출, C++ 호출과 다름)를 얻습니다. 최상위 레벨 설치자 객체에 대한 UILevel 속성을 설정하여 사용자가 말하는 GUI를 표시하지 않습니다. 업그레이드 코드를 얻는 다른 방법은 WMI를 사용하는 것입니다 :'Select * from Win32_Property Where Property = 'UpgradeCode ''. 특정 제품 코드의 경우 : 'SELECT * FROM Win32_Property WHERE 속성 = 'UpgradeCode'AND ProductCode = '{B862B671-59FD-7457-AFA0-C738FB7ABD60}' '. 아마도이 정보가 VBScript 임에도 불구하고 아래에 답변을 추가해야합니다. –

답변

3

MsiOpenProduct는 괜찮습니다. 시퀀스 나 동작을 실행하지 않는 한 아무 작업도 수행하지 않습니다. 대화 상자를 닫으려면 MsiSetInternalUI() 또는 MsiSetExternalUI()를주의하여 사용할 수 있습니다.

당신만큼 ProductCodeUpgradeCode로 (만큼 그들은 변환에 의해 변경되지 않는 한, 즉) 정적 안전하고, 취할 수있는 또 다른 방법은, MsiGetProductInfo를 (사용하여 데이터베이스를 찾을 수)와 그에 MsiOpenDatabase()를 호출하는 것입니다 . 차이점은 MsiOpenProduct() (또는 비슷한 MsiOpenPackage)는 설치시 사용 된 변환을 적용하고 세션을 준비하지만 MsiOpenDatabase()는 수행하지 않습니다.

+0

저에게 완벽하게 작동합니다. MsiGetProductInfo는 내가 필요한 것입니다. –

1

원하는 정보를 얻으려면 :: MsiGetProductInfo()를 호출하면됩니다. :: MsiOpenDatabase() 매우 느린 작업 :: 동안 MsiGetProductInfo() (IIRC) 더 레지스트리 조회와 동등합니다.

+0

사실 일 수도 있지만 위와 같이 쓴 것처럼 MsiGetProductInfo를 통해 업그레이드 코드를 얻을 방법이 없습니다. 제한된 속성 집합 만 쿼리 할 수있는 것 같습니다. 속성 목록을 보려면 http://msdn.microsoft.com/en-us/library/aa370130%28VS.85%29.aspx를 참조하십시오. – Hatch

+0

아, 네 말이 맞아. 목록에서 UpgradeCode를 잘못 기억했습니다. –

+0

이 문제에 대한 정보를 찾을 때이 질문을 다시 보지 않았습니다. WMI를 사용하여 업그레이드 코드를 검색했지만 MSI API를 사용하여 다시 시도했습니다. VBScript에서 여기에 별도의 답변으로 추가되었습니다. MSI API는 WMI보다 2 ~ 3 배 빠른 속도로 작동하지만 여전히 느립니다. 적어도 말하기에는 좋지 않지만 내가 필요한 것을보고합니다. ** 많은 세션 객체를 회전시키는 것에 대한 생각? ** 자바 스크립트는 완전히 실패했습니다. 동시에 열리는 세션에 걸림돌이되었습니다 (저의 가난한 자바 기술 일 수 있습니다). 지금까지 VBScript를 사용하는 모든 세션 개체에서 부작용을 보지 못했습니다. –

0

VBScript를 여기 WMI파워 쉘 또는 를 사용하여 UpgradeCode을하는 방법에 대한 정보를 포괄적 인 답이있다 : 아래

How can I find the Upgrade Code for an installed MSI file?이 VBScript를/COM 자동화를 사용하여 빠르고, 기본적인 예입니다 (WMI가 아닌 MSI API) 및 OP (OpenProduct 메서드 사용 - Win32 설치 프로그램 함수와 동등한 COM 사용)에서 설명하는 방법


위의 내 설명에서 설명한대로 OP와 C++에서 동일한 작업을 수행하기 위해이 작은 VBScript를 추가합니다. Windows InstallerWMI (Win32_Product 개체), COM automationWin32 C++ installer functions을 통해 액세스 할 수 있습니다.

패키지에 대한 UpgradeCode은 COM API 또는 Win32 API에서 직접 사용할 수없는 것으로 나타납니다. 이 Installer.RelatedProducts 같은 기능에 입력 매개 변수가 특히 때문에, 실제로 아주 이상한 - 그것은 실제 호출이 RelatedProducts(UpgradeCode)을해야 문서에서 명확하지 않다, 그러나에보고 msi.IDL 당신이 볼 : StringList* RelatedProducts([in] BSTR UpgradeCode);

의 WMI 옵션이 작동하지만, 이 OpenProduct 호출은 아래에 설명되어 있습니다 (훨씬 빠르며 안전하게 나타납니다 - WMI는 내가 아는 한 완전히 읽기 전용이지만 - 천국은 "후드"에서 무엇을하는지 알고 있습니다.) 세션 객체를 회전시키고 있습니까? 또는 WMI 데이터베이스에서 읽는 중입니까? WMI는 어떻게 든 더 안전하다고 느낍니다.)

아래의 방법의 장점은 설치시 해당 제품에 적용된 모든 변환을 적용한다는 것입니다. 메시지 상자를 표시하는 대신 디스크에 쓰고 싶거나 문서를 찾는 데 귀찮은 경우가 있습니다. 패키지 정보를 바탕 화면 텍스트 파일에 쓰는 유사한 VBScript는 다음과 같습니다. How can I find the product GUID of an installed MSI setup? - 페이지 아래쪽에 약간 씩 복사하면됩니다. 몇 줄 및 당신은 메시지 상자 무료입니다).

On Error Resume Next ' This "tersified" script has no error handling 

Const msiUILevelNone = 2 
Set installer = CreateObject("WindowsInstaller.Installer") 
Set products = installer.ProductsEx("", "", 7) 
installer.UILevel = msiUILevelNone ' Suppress GUI (MSI progress dialog) 

'Iterate over all MSI packages on the box 
For Each product In products 
    ' productcode = product.ProductCode 
    ' name = product.InstallProperty("ProductName") 
    ' version = product.InstallProperty("VersionString") 
    ' pkgcode = product.InstallProperty("PackageCode") 

    Set session = installer.OpenProduct(product.ProductCode) 
    upgradecode = session.ProductProperty("UpgradeCode") 
    MsgBox upgradecode 
    Set session = Nothing ' Important, close the session (doesn't work in Javascript btw) 

    Exit For ' End after one iteration (so you don't get a million message boxes) 
       ' Alternatively something like: If i > 4 Then Exit For 
Next 

Set installer = Nothing 

MsgBox "Finished" 

은 내가 UpgradeCode를 검색하는 다른 방법에 대한 C++에서 Win32 설치 기능에보고하는 것을 시도했다, 그러나 나는 분명 아무것도 볼 수 없습니다. 세션 접근법은 C++에서도 잘 작동하지만, 핸들과 리소스의 릴리즈에 대해서는 조금 불안합니다. 나는 C++로 제대로 사소한 훈련을받지 못했지만 위험 할 정도로 충분한 것을 알고 있습니다. 구멍에 불이입니다. 기타 ...

OP가 상자에있는 모든 패키지를 검색했는지 아니면 하나만 가져 왔는지 궁금합니다. 타이밍 문제와 자바 스크립트에서 볼 수있는 동시 세션 객체 문제가 C++에서도 발생하는지 궁금합니다. 나는 언젠가 그것을 생각할 것이다.

관련 문제