Тип диска m ["Емкость"] - UInt64. Я использовал эту функцию, чтобы узнать, какой тип данных использовался.
m["Capacity"].GetType().ToString();
Я изменил CLR для вывода только типа данных для этой цели.
Зная тип, я провел некоторое исследование, как конвертировать UInt64 в Int64, и, наконец, нашел подход:
Int64 int64cap;
Int64.TryParse(m["Capacity"].ToString(), out int64cap);
Я не знаю, правильное ли это решение, но оно работает для меня.
Вот полный код
public class WMIQuery
{
[SqlFunction(FillRowMethodName = "FillRow")]
public static IEnumerable InitMethod()
{
ManagementScope scope = new ManagementScope();
scope = new ManagementScope(@"\\localhost\root\CIMV2");
scope.Connect();
SelectQuery query = new SelectQuery("SELECT Name, Capacity, Freespace FROM Win32_Volume WHERE DriveType=3");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection retObjectCollection = searcher.Get ( );
return retObjectCollection;
}
public static void FillRow(Object obj, out SqlString Name, out SqlDecimal Capacity, out SqlDecimal Freespace)
{
ManagementObject m = (ManagementObject)obj;
Name = new SqlString((string)m["name"]);
Int64 int64cap;
Int64.TryParse(m["Capacity"].ToString(), out int64cap);
decimal decCap;
decCap = int64cap / 1073741824; // to GB
decCap = Math.Round(decCap, 2);
Capacity = new SqlDecimal(decCap);
Int64 int64Free;
Int64.TryParse(m["Freespace"].ToString(), out int64Free);
decimal decFree;
decFree = int64Free / 1073741824; // to GB
decFree = Math.Round(decFree, 2);
Freespace = new SqlDecimal(decFree);
}
}
SQL для запуска этого материала:
CREATE ASSEMBLY [MyFirstAssembly]
FROM 'C:\MyFirstAssembly.dll'
WITH PERMISSION_SET = UNSAFE
GO
CREATE FUNCTION [dbo].[WMIQuery]()
RETURNS TABLE (
[Name] [nvarchar](4000) NULL,
[Capacity] decimal(18,2) NULL,
[Freespace] decimal(18,2) NULL
) WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [MyFirstAssembly].[WMIQuery].[InitMethod]
GO
select * from WMIQuery()
Я думаю, что нет никакого "чистого" способа сделать это, потому что msi проект должен смочь удалить себя полностью дизайном. Я думаю лучший способ решить это, при помощи пользовательского действия, которое выполняет пакетный файл и помещает Вашу логику обновления configfile в тот пакетный файл. Пользовательское действие похоже на это (только соответствующие части):
<Directory Id="MYDIR" Name="MyDir">
<Component Id="update.cmd" Guid="YOUR-GUID">
<File Id="update.cmd" Name="update.cmd" KeyPath="yes"
Source="source\update.cmd" />
</Component>
</Directory>
<CustomAction Id='RunUpdate' Directory='MYDIR'
ExeCommand='[SystemFolder]cmd.exe /c update.cmd' Return='ignore'/>
<InstallExecuteSequence>
<Custom Action='RunUpdate' After='InstallFinalize'>NOT Installed</Custom>
</InstallExecuteSequence>
Моя рекомендация состоит в том, чтобы обычно иметь пользователя доступное для редактирования содержание в отдельном файле и управлять этим с помощью приложения вместо установки. Это также означает, что отдельный файл является "пользовательским содержанием" и должен быть упущен из установки.
Я нашел попытку сделать миграцию пользовательских данных декларативно, чтобы быть обманчиво трудным. При попытке сделать это во время установки, когда необходимо продумать установку, удаление, восстановление, исправив и откат для всех тех случаев только, делает это хуже.
Например, что поведение об/мин делает на "восстановлении". Скопируйте пользовательские данные из пути и замените его хорошим файлом? Это - вероятно, корректные 60% - 80% времени. И удалите, файл должен быть удален? Это хитро, если пользователь собирается просто обновить до следующей версии.
Снова, лучше чтобы позволить им решить, что сделать с их тонкими настройками к конфигурации. По моему скромному мнению.