Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/8: Рейтинг темы: голосов - 8, средняя оценка - 5.00
0 / 0 / 0
Регистрация: 04.09.2018
Сообщений: 10
1
Builder 6

ShellExecute не работает без OpenDialog, хотя последний там никаким боком

04.09.2018, 18:32. Показов 1517. Ответов 14

Author24 — интернет-сервис помощи студентам
Всем доброго времени суток.

Пишу простейшую программу, которая открывает файл.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//---------------------------------------------------------------------------
 
#include <vcl.h>
#pragma hdrstop
 
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------
 
 
void __fastcall TForm2::Button1Click(TObject *Sender)
{
//OpenDialog1->Execute();
AnsiString Pth = Edit1->Text;
ShellExecute(0, 0, "FFD.exe", Pth.c_str(), 0, SW_SHOW);
Application->Terminate();
 
 
}
//---------------------------------------------------------------------------
void __fastcall TForm2::FormCreate(TObject *Sender)
{
 
}
//---------------------------------------------------------------------------
Как итог, если строка
C++
1
OpenDialog1->Execute();
закомментирована (или её нет), файл не открывается. Но всё работает если я выберу файл который нужен(или даже любой другой.) . Прошу помощи, ведь руки у меня кривые, а в своём глазу соринки не вижу.

P.S. Form1 и Form2 связаны только одним: одна показывает другую по нажатию на кнопку .Shellapi инклюднут в Unit1.cpp
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
04.09.2018, 18:32
Ответы с готовыми решениями:

В компе дисковод показывает, что там есть диск (на нём игра, открываются все папки), хотя его там нет! Другие диски не видит. Пишет "Вставьте диск"
В компе дисковод показывает, что там есть диск (на нём игра, открываются все папки), хотя его там...

Почему я не могу ввести строчку используя меню, хотя программа работает без него
#include &quot;stdafx.h&quot; #include &quot;iostream&quot; #include &lt;stdio.h&gt; #include &lt;locale.h&gt; #include...

Диск С переполнен, хотя там файлов на половину объема.
Комп всячески бьет тревогу, что диск С в опасности, хотя у меня заполнено даже меньше половины...

Флешка на половину занята, хотя там ничего нет.
Короче вставляю влеху а на ней ничего, хотя она на половину занята, так оказывает ос что делать?

14
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
32835 / 21172 / 8148
Регистрация: 22.10.2011
Сообщений: 36,431
Записей в блоге: 8
04.09.2018, 18:44 2
Перед вызовом ShellExecute нужно инициализировать COM, поскольку вызова CoInitialize/CoInitializeEx у тебя в коде нет - ничего и не работает. А вот при вызове OpenDialog1->Execute COM корректно инициализируется, и уже можно продолжать вызывать все зависящие от этого функции API.

Так что курить надо в сторону CoInitialize и не забывать про CoUninitialize
0
0 / 0 / 0
Регистрация: 04.09.2018
Сообщений: 10
04.09.2018, 18:55  [ТС] 3
Спасибо за ответ, но можете подробнее описать, функции CoInitialize и CoUninitialize? Я тут погуглил, но ничего не работает.
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
32835 / 21172 / 8148
Регистрация: 22.10.2011
Сообщений: 36,431
Записей в блоге: 8
04.09.2018, 19:17 4
Очень интересно. Сделал новый тестовый проект на BCB6, вообще ничего нигде не прописывал, никаких инклудов, просто добавил кнопку и в ее обработчике написал:
C++
1
2
3
4
5
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString path = "C:\\MyPrograms";
    ::ShellExecute(0, 0, path.c_str(), 0, 0, 1);
}
Все прекрасно отработало, безо всяких лишних движений. Значит, что-то в проекте мешает ShellExecute-у отработать, нужно весь проект видеть.
0
Практикантроп
4826 / 2718 / 526
Регистрация: 23.09.2011
Сообщений: 5,777
04.09.2018, 19:37 5
OpenDialog- долгоиграющая процедура... . Я бы присмотрелся к Application->Terminate, ибо всё это в одной упряжке ( ?!! ) _
0
0 / 0 / 0
Регистрация: 04.09.2018
Сообщений: 10
04.09.2018, 21:07  [ТС] 6
volvo, все файлы проекта на Яндекс.Диске


nick42, без Application->Terminate всё так-же.
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
32835 / 21172 / 8148
Регистрация: 22.10.2011
Сообщений: 36,431
Записей в блоге: 8
04.09.2018, 22:40 7
C++
1
2
3
4
5
6
7
8
9
void __fastcall TForm2::Button1Click(TObject *Sender)
{
CoInitialize(0); // Скобки у тебя где? Параметр где?
AnsiString Pth = Edit1->Text.c_str();
ShellExecute(0, 0, "FFD.txt", Pth.c_str(), 0, SW_SHOW);
ShowMessage("Secceseful");
CoUninitialize(); // Скобки где?
// Application->Terminate();
}
Это не Дельфи все-таки, а Билдер. Надо писать синтаксисом C++.

Но лучше CoInitialize вызвать в OnCreate формы, а CoUninitialize - в OnDestroy.
0
0 / 0 / 0
Регистрация: 04.09.2018
Сообщений: 10
04.09.2018, 23:11  [ТС] 8
volvo, всё поправил как Вы сказали, но ничего не изменилось.
0
1280 / 598 / 116
Регистрация: 18.08.2009
Сообщений: 832
05.09.2018, 09:30 9
MatveiZ, та зачем тебе этот ShellExecute сдался?

Вот так напиши и будет тебе счастье
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
STARTUPINFO si;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(si);
 
PROCESS_INFORMATION processInformation;
memset(&processInformation, 0, sizeof(PROCESS_INFORMATION));
 
const AnsiString sCMD = /*лучше указать полный путь к файлу*/"FFD.exe " + 
    /*если параметр в виде файла, то лучше взять в кавычки*/Edit1->Text;
 
if (!CreateProcess(NULL, sCMD.c_str(), NULL, NULL, 0, 0, NULL, NULL/*сюда написать текущую директорию, если нужно*/, &si,
        &processInformation)) {
    ShowMessage(SysErrorMessage(GetLastError()));
}
0
0 / 0 / 0
Регистрация: 04.09.2018
Сообщений: 10
05.09.2018, 15:27  [ТС] 10
Maluda, выбивает в "Не удаётся найти указанный файл".
0
1280 / 598 / 116
Регистрация: 18.08.2009
Сообщений: 832
05.09.2018, 16:32 11
Цитата Сообщение от MatveiZ Посмотреть сообщение
выбивает в "Не удаётся найти указанный файл".
Цитата Сообщение от Maluda Посмотреть сообщение
лучше указать полный путь к файлу
Я же знал, что такое будет Поэтому напиши полный путь к файлу или укажи текущую директорию туда, где он лежит.

Добавлено через 3 минуты
Пример 1:
C++
1
2
CreateProcess(NULL, "notepad.exe c:/Windows/System32/drivers/etc/hosts",
NULL, NULL, 0, 0, NULL, "c:/Windows/System32", &si, &processInformation)
Пример 2:
C++
1
2
CreateProcess(NULL, "c:/Windows/System32/notepad.exe c:/Windows/System32/drivers/etc/hosts",
NULL, NULL, 0, 0, NULL, NULL, &si,&processInformation)
0
0 / 0 / 0
Регистрация: 04.09.2018
Сообщений: 10
05.09.2018, 16:36  [ТС] 12
Maluda, я понимаю, но этот файл может лежать в разных директориях.
P.S. воспользоваться OpenDialog'ом не позволяет религия.
0
1280 / 598 / 116
Регистрация: 18.08.2009
Сообщений: 832
05.09.2018, 17:26 13
Лучший ответ Сообщение было отмечено MatveiZ как решение

Решение

CreateProcess без указания пути будет искать:
1. Каталог, из которого загружена прикладная программа.
2. Текущий каталог родительского процесса.
3. 32-разрядный системный каталог Windows. Используйте функцию GetSystemDirectory, чтобы получить путь к этому каталогу. Имя (название) этого каталога - System32.
4. 16-разрядный системный каталог Windows. Нет функции, которая получает путь к этому каталогу, но он находится. Имя этого каталога - SYSTEM.
5. Каталог Windows. Используйте функцию GetWindowsDirectory, чтобы получить путь к этому каталогу.
6. Каталоги, которые внесены в список в PATH переменной окружения.

ShellExecute всё тоже самое и
7. The per-application path specified by the App Paths registry key

Допил CreateProcess, чтобы открывал файлы идентично ShellExecute

В этом примере задача открыть приложение chrome.exe с передачей параметра в виде сайта google.com

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <memory>
#include <Registry.hpp>
 
AnsiString sExeName = "chrome.exe";
const AnsiString sParams = "google.com";
 
AnsiString sFolder = "";
 
// пробуем найти файл в реестре, в разделе "App Paths"
std::auto_ptr<TRegistry>ARegistryPtr(new TRegistry());
ARegistryPtr->RootKey = HKEY_LOCAL_MACHINE;
if (ARegistryPtr->KeyExists("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" + sExeName)) {
    if (ARegistryPtr->OpenKeyReadOnly("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" + sExeName)) {
        sExeName = ARegistryPtr->ReadString(""); // определяется в реестре как значение по умолчанию
        sFolder = ARegistryPtr->ReadString("Path");
        
        ARegistryPtr->CloseKey();
    }
}
 
 
STARTUPINFO si;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(si);
 
PROCESS_INFORMATION processInformation;
memset(&processInformation, 0, sizeof(PROCESS_INFORMATION));
 
const AnsiString sCMD = sExeName + " " + sParams;
 
if (!CreateProcess(NULL, sCMD.c_str(), NULL, NULL, 0, 0, NULL, sFolder.IsEmpty() ? NULL : sFolder.c_str(), &si, &processInformation)) {
    ShowMessage(SysErrorMessage(GetLastError()));
}
2
61 / 50 / 12
Регистрация: 25.01.2010
Сообщений: 255
09.09.2018, 04:12 14
Цитата Сообщение от volvo Посмотреть сообщение
Перед вызовом ShellExecute нужно инициализировать COM, поскольку вызова CoInitialize/CoInitializeEx у тебя в коде нет - ничего и не работает. А вот при вызове OpenDialog1->Execute COM корректно инициализируется, и уже можно продолжать вызывать все зависящие от этого функции API
volvo, вы меня удивляете
C++
1
OpenDialog1->Execute();
Задает текущую директорию, затем, все файлы ищутся в ней.
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
32835 / 21172 / 8148
Регистрация: 22.10.2011
Сообщений: 36,431
Записей в блоге: 8
09.09.2018, 10:48 15
Цитата Сообщение от samsebe Посмотреть сообщение
вы меня удивляете
Аналогично. Посмотреть исходники метода Execute - никак? Ну хорошо:
Delphi
1
2
3
4
function TOpenDialog.Execute(ParentWnd: HWND): Boolean;
begin
  Result := DoExecute(@GetOpenFileName, ParentWnd);
end;
Особенно внимательно смотрим на первый параметр DoExecute. Это та самая WinAPI-шная функция GetOpenFileName, которая требует CoInitialize для корректной работы. Что и делает класс TOpenDialog, не надеясь на то, что пользователь сделает это самостоятельно. А уж то, что она меняет текущую директорию - это уже побочный эффект. К тому же, ты не телепат, и состояние свойства ofNoChangeDir у экземпляра TOpenDialog тебе не известно. Так что утверждать, что оно что-то там меняет - вообще некорректно.
0
09.09.2018, 10:48
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
09.09.2018, 10:48
Помогаю со студенческими работами здесь

Наушники earpods отображаются как микрофон,хотя его там нет
Доброго времени суток,знатоки. В общем столкнулся с проблемой,имеется ноутбук с вебкамерой и...

ShellExecute не работает
Доброго времени суток. Вот такая задачка хочу открыть программу через OpenDialog вот пример : ...

Не работает ShellExecute
Пишет unit2.pas(40,67) Error: Identifier not found &quot;SW_RESTORE&quot; procedure...

Не работает ShellExecute!
Не поможете?

Не работает ShellExecute
На компе не срабатывает кнопка с кодом void __fastcall TForm1::Button1Click(TObject *Sender) {...

ShellExecute не работает
Ктонить подскажет, почему вот такой код не работает? ShellExecute(Handle, 'open', 'cmd.exe', '/c...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru