Как загрузить установщик MSI с аргументом для идентификатора пользователя
У меня есть приложение .NET С#, завернутое в установщик MSI - "myprogram.exe". У меня есть сайт PHP и конкретная страница, где пользователь может загрузить программу по ссылке.
Я хотел бы отслеживать определенные события в приложении .NET. Например, "Программа открыта".
Легко отправлять события на мой сервер, однако как я могу получить идентификатор пользователя с сервера php, поэтому я могу узнать, какой пользователь сделал то, что в приложении .NET?
Я думал о передаче аргумента (идентификатора пользователя) в установщик MSI, но не смог найти способ.
Как мне связать между идентификатором пользователя PHP и .NET?
Уточнение -
Многие люди предлагали использовать систему входа для привязки между сервером и приложением.
Это действительно самое простое решение, однако на моем веб-сайте я не заставляю пользователя входить в систему для загрузки приложения (и я не запрашиваю данные для входа в приложение .NET - его необязательно). Если нам не нужно запрашивать данные для входа, я думаю, что нам не следует, опыт для пользователя будет намного лучше (гораздо меньше шагов для использования приложения) - больше шансов для загрузки и использования приложения Desktop.
Учтите, что текущий поток → Веб-страница - Загрузить клик - Запустить - Использовать приложение
(занимает 10 секунд)
С логином → Веб-страница - Зарегистрируйтесь (подтвердите адрес электронной почты?) - Перенаправление - Загрузите Click-run - приложение Войти - Используйте приложение
(для пользователя требуется 60-120 секунд)
Ответы
Ответ 1
Вход из программы
Лучший способ - позволить пользователю войти в систему с теми же учетными данными в вашей программе. Таким образом, ваша программа может использовать безопасную аутентификацию OAuth2 для связи с вашим внутренним API. Это также делает прозрачным для пользователя, что программа взаимодействует с Интернетом.
Включить идентификатор пользователя в имя файла
Другой способ - добавить идентификатор пользователя в имя файла установщика во время загрузки и извлечь его при запуске установщика. Вам нужно будет проверить, позволяет ли это средство установки. Кроме того, делайте это только в том случае, если ваш идентификатор пользователя UUID или что-то подобное, так как вы не хотите, чтобы пользователь угадывал другие идентификаторы.
App.config
Третий вариант - добавить идентификатор пользователя в файл App.config
. Существует два способа сделать это:
- Создайте свой .msi с
App.config
несжатым, добавьте параметр идентификатора пользователя с фиксированным UUID. Ваш PHP скрипт может искать UUID и заменять его в двоичном формате .msi перед его отправкой пользователю. См. Фрагмент кода в преобразовании MST
- Создайте .msi по запросу с помощью настраиваемого
App.config
. Это будет работать, только если ваш веб-сервер работает в Windows или у вас есть удаленный сервер сборки Windows, который может выполнять эту работу.
Преобразование MST
Вы также можете использовать преобразование MST и использовать тот же двоичный метод замены, как я объяснил для пункта 1 в разделе App.config.
Для обеих опций вы можете использовать PHP script, который использует двоично-безопасные функции для замены значений в установщике и отправляет файл пользователю в качестве загрузки:
<?php
$userId = // TODO get userId from the session or database
$data = file_get_contents("./my-installer.msi");
// I would use UUID for template and userId, this way the size of the installer remains the same after replace
$data = str_replace("{fe06bd4e-4bed-4954-be14-42fb79a79817}", $userId, $data);
// Return the file as download
header("Cache-Control: public"); // needed for i.e.
header('Content-Disposition: attachment; filename=my-installer.msi');
header('Content-Type: application/x-msi');
header("Content-Transfer-Encoding: Binary");
echo $data;
?>
Серийный номер
Последний способ, о котором я могу думать, - позволить программе запрашивать серийный номер при первом запуске и позволить вашему сайту генерировать уникальный серийный номер для каждого пользователя.
Ответ 2
Um OK, обратите внимание, что это очень вероятно, что это не, что вы хотите сделать. Тем не менее я объясню пару способов сделать это.
Использование файлов MST с MSI:
Вы можете создавать файлы MST с свойством идентификатора пользователя и генерировать их для каждого пользователя, когда они загружают msi и заставляют их устанавливать msi с преобразованием:
msiexec -i c:\temp\The.msi transforms=c:\temp\YourPerso.mst
Подробнее см. здесь: Установить преобразование с помощью командной строки.
Вы видите, что файлы MST много используются в крупных организациях, где все MSI имеют файлы MST с серийными номерами и т.д..
Для создания MST файла вам необходимо загрузить и установить Microsoft Orca Tool, его часть SDK Microsoft Windows.
Откройте Orca и создайте файл MST из файла MSI. В основном вы открываете файл MSI, переходите к таблице "Свойство", там вы видите список параметров.
Обратите внимание, что в файле MSI вы увидите параметры, требующие значения по умолчанию.
Прежде чем добавлять/изменять параметры, создайте новое преобразование, нажав в меню "Трансформация" → "Новое преобразование".
![введите описание изображения здесь]()
Затем вы можете изменять параметры или добавлять новые, как хотите. Когда вы закончите изменение параметров, используйте функцию "Generate Transform" в меню "Transform", чтобы сгенерировать MST файл.
![введите описание изображения здесь]()
Если вы откроете файл mst с помощью HexEditor, вы увидите только что добавленное свойство:
![введите описание изображения здесь]()
Вы можете отредактировать файл для каждой загрузки, просто отредактировав значение, например:
![введите описание изображения здесь]()
Вы, конечно, можете (и, вероятно, должны) сделать это с помощью API-интерфейса WindowsInstaller.Installer. Вот пример:
private function createTransform(mstfile, msi, config)
writeLog InfoLog, "Generating transform " & mstfile
dim vars: set vars = configvars(config)
dim createPropertyTable: createPropertyTable = "create table `Property` " & _
"(`Property` char(72) not null, `Value` longchar localizable " & _
"primary key `Property`)"
dim addProperty: addProperty = "insert into `Property` (`Property`, `Value`) values (?, ?)"
dim updateProperty: updateProperty = "update `Property` set `Value` = ? where `Property` = ?"
dim wi: set wi = createObject("WindowsInstaller.Installer")
dim base: set base = wi.openDatabase("base.msi", msiOpenDatabaseModeCreate)
base.openview(createPropertyTable).execute
dim tgt: set tgt = wi.openDatabase("tgt.msi", msiOpenDatabaseModeCreate)
tgt.openview(createPropertyTable).execute
dim props: set props = createObject("scripting.dictionary")
dim view: set view = msi.openView("select `Property`, `Value` from `Property`")
view.execute
dim record: set record = view.fetch
while not record is nothing
props(record.stringdata(1)) = true
base.openview(addProperty).execute record
tgt.openview(addProperty).execute record
set record = view.fetch
wend
set record = wi.createRecord(2)
dim prop
for each prop in properties_
on error resume next
dim val: val = expand(vars, prop(DepPropertyValueIdx))
if err then
writeLog ErrorLog, err.description
exit function
end if
on error goto 0
writeLog InfoLog, "Property " & prop(DepPropertyNameIdx) & "=" & val
if props.exists(prop(DepPropertyNameIdx)) then
record.stringdata(2) = prop(DepPropertyNameIdx)
record.stringdata(1) = val
tgt.openview(updateProperty).execute record
else
record.stringdata(1) = prop(DepPropertyNameIdx)
record.stringdata(2) = val
tgt.openview(addProperty).execute record
end if
next
if not tgt.generateTransform(base, mstfile) then
writeLog ErrorLog, "Failed to create transform"
exit function
end if
tgt.createTransformSummaryInfo msi, mstfile, 0, 0
createTransform = true
end function
Совет: Для этого с помощью управляемого кода вам лучше всего использовать Microsoft.Deployment.WindowsInstaller.dll
, которые доступны как часть < а6 >
Создайте MSI для каждого пользователя:
IMHO было бы намного проще сделать это с помощью Nullsoft (WiX, InstallShield, INNO и т.д.) и построить MSI для каждого пользователя. Для этого вы должны вставлять уникальный идентификатор пользователя, например, nsi script и запускать сборку MSI для каждой загрузки. Во время установки уникальный идентификатор пользователя будет храниться в файле, в разделе реестра или т.д. Я предлагаю вам воспользоваться этим NSIS Wizard Editor чтобы быстро взломать базовую установку NSI script и построить MSI через командную строку: makensis.
Примечание.. Хотя "Включение идентификатора пользователя в имя файла MSI" проще, чем создание MSI для каждого пользователя, пользователи могут легко изменить имя файла. Его гораздо меньше вероятность, что пользователь проверит MSI с помощью Orca, чтобы найти встроенный идентификатор пользователя.
Самый простой и логичный способ:
Легко отправлять события на мой сервер, однако как я могу захватить user-id с php-сервера, поэтому я могу узнать, какой пользователь сделал что-то в приложении .NET?
Сделайте то, что @Jhuliano Moreno, а затем @WouterHuysentruit рекомендуется:
Когда ваше приложение запускается в первый раз, просто заставьте пользователя войти в программу, используя учетные данные своего веб-сайта, и запишите свой идентификатор пользователя в файле конфигурации, разделе реестра или записи базы данных. В основном создайте файл cookie, чтобы вы узнали их в следующий раз, когда откроете программу, или сделайте их логин каждый раз.
Ответ 3
Когда файл вызывается, посылает параметр UserID, если вы используете структуру MVC в своем PHP, вам нужен новый контроллер, который получает файл msi, и переименовывает его в name-userID.exe, а затем возвращает файл для загрузки через браузер.