| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | «  : 25-07-2012 17:30 »  |  | 
 
 Есть у нас приложение, интенсивно работающее с памятью и DirectX (т.е. в том числе видеопамятью). И вот стоит в этом приложении вызвать стандартный OpenFileDialog в multiselect режиме, выбрать пару файлов в некоторых (но не всех подряд) папках, как стек процесса разрушается, а затем происходит глобальный сбой видеодрайвера и кратковременное отключение монитора до перезагрузки видеоподсистемы Windows. Причём наблюдается это не на всякой машине. Без вызова OpenFileDialog всё работает стабильно. 0) Отчего сие? Это вопрос философский, риторический. Живо напоминает: Мои папа и мама! Я живу хорошо, просто замечательно. У меня все есть, есть свой дом, он теплый. В нем одна комната и кухня. Я без вас очень скучаю, особенно по вечерам. А здоровье мое не очень. То лапы ломит, то хвост отваливается. А на днях я линять начал. Старая шерсть с меня сыпется, хоть в дом не заходи. Зато новая растет чистая, шелковистая, так что лохматость у меня повысилась. До свидания, ваш сын дядя Шарик. В любом случае такое поведение предвосхищает ожидания заказчика... 1) Есть ли какие-то способы поправить дело без написания собственного диалога? |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| RXL | 
								|  | « Ответ #1 : 25-07-2012 19:22 »  |  | 
 
 Дим, а данный кусочек кода покажешь?
 Версия винды? Битность? Версия .NET?
 |  
						| 
								|  |  
								| « Последнее редактирование: 25-07-2012 19:28 от RXL » |  Записан | 
 
 ... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С. |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #2 : 25-07-2012 19:55 »  |  | 
 
 в WinAPI  (вернее, я из-под MFC) такое тоже случается именно с этим же диалогом, если неправильно задать параметры в конструкторе и структуре OPENFILENAME. Можно неплохо нарваться на неприятные вещи ) А именно, следующий момент:http://msdn.microsoft.com/en-us/library/wh5hz49d(v=vs.80).aspx RemarksEither a File Open or File Save As dialog box is constructed, depending on the value of bOpenFileDialog.
 
 To allow the user to select multiple files, set the OFN_ALLOWMULTISELECT flag before calling DoModal. You need to supply your own filename buffer to accommodate the returned list of multiple filenames. Do this by replacing m_ofn.lpstrFile with a pointer to a buffer you have allocated, after constructing the CFileDialog, but before calling DoModal. Additionally, you must set m_ofn.nMaxFile with the number of characters in the buffer pointed to by m_ofn.lpstrFile. If you set the maximum number of files to be selected to n, the necessary buffer size is n*(_MAX_PATH + 1) + 1.
 надеюсь, помог ) |  
						| 
								|  |  
								| « Последнее редактирование: 26-07-2012 16:03 от Алексей1153++ » |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #3 : 26-07-2012 12:30 »  |  | 
 
 Алексей1153++, да, в MFC-версии у нас то же самое. И описанный в заметке "хак" с буфером приделан.RXL , ну что там за кусочек... Самый обычный мирный кусочек:             OpenFileDialog dialog = new OpenFileDialog();dialog.Multiselect = true;
 dialog.SupportMultiDottedExtensions = true;
 dialog.AutoUpgradeEnabled = true;
 dialog.Filter = "DICOM slices (*.dcm)|*.dcm|All files (*.*)|*.*";
 dialog.FilterIndex = 0;
 dialog.RestoreDirectory = true;
 dialog.CheckPathExists = true;
 dialog.CheckFileExists = true;
 dialog.ValidateNames = true;
 DialogResult result = dialog.ShowDialog(this);
 if (result == DialogResult.OK)
 {
 // ...
 Из которого лезет такое... Попробую на WinAPI. |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #4 : 26-07-2012 16:11 »  |  | 
 
 dialog.Filter = "DICOM slices (*.dcm)|*.dcm|All files (*.*)|*.*";
 не знаю, как шарповая,но винапишная версия требует наличия 0-терминаторов после каждой подписи и маски + ещё один дополнительный в конце то есть так: "DICOM slices (*.dcm)\0 *.dcm\0 All files (*.*)\0 *.*\0\0 "; (ну да, синий терминатор тут показан для наглядности, на самом деле его вставит компилятор, так как это строковая константа) dialog.FilterIndex = 0;
 а тут индекс должен начинаться от 1 , а не от 0 |  
						| 
								|  |  
								| « Последнее редактирование: 27-07-2012 02:48 от Алексей1153++ » |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #5 :  26-07-2012 16:34 »   |  | 
 
 Алексей1153++, не, разделители там правильные, а насчёт индекса согласен, только не помогает. База на WinAPI + STL #include <iostream>#include <list>
 #include <string>
 #include <Windows.h>
 
 using namespace std;
 
 int main()
 {
 const int bufferSize = MAX_PATH * 1000;
 wchar_t buffer[bufferSize];
 ZeroMemory(buffer, sizeof(buffer));
 OPENFILENAMEW openFileName;
 openFileName.lStructSize = sizeof(OPENFILENAMEW);
 openFileName.hwndOwner = NULL;
 openFileName.lpstrFile = buffer;
 openFileName.lpstrFile[0] = L'\0';
 openFileName.nMaxFile = bufferSize;
 openFileName.lpstrFilter = L"DICOM slices (*.dcm)\0*.dcm\0All\0*.*\0";
 openFileName.nFilterIndex = 1;
 openFileName.Flags = OFN_ALLOWMULTISELECT | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER;
 openFileName.FlagsEx = 0;
 openFileName.hInstance = NULL;
 openFileName.lCustData = NULL;
 openFileName.lpfnHook = NULL;
 openFileName.lpstrCustomFilter = NULL;
 openFileName.lpstrDefExt = NULL;
 openFileName.lpstrFileTitle = NULL;
 openFileName.lpstrInitialDir = NULL;
 openFileName.lpstrTitle = NULL;
 openFileName.lpTemplateName = NULL;
 openFileName.nFileExtension = 0;
 openFileName.nFileOffset = 0;
 openFileName.nMaxCustFilter = 0;
 openFileName.nMaxFileTitle = 0;
 openFileName.pvReserved = NULL;
 openFileName.dwReserved = 0;
 BOOL result = GetOpenFileNameW(&openFileName);
 if(result != 0)
 {
 wstring path;
 list<wstring> files;
 int i = 0;
 for(; openFileName.lpstrFile[i] != NULL; i += 1)
 {
 wstring file;
 for(; openFileName.lpstrFile[i] != NULL; i += 1)
 {
 file.push_back(openFileName.lpstrFile[i]);
 }
 if(path.size() == 0)
 {
 path = file;
 }
 else
 {
 wstring fullPath = wstring(path).append(L"\\").append(file);
 files.push_back(fullPath);
 }
 }
 if(files.size() == 0 && path.size() > 0)
 {
 files.push_back(path);
 }
 for(list<wstring>::iterator i = files.begin(); i != files.end(); i++)
 {
 wcout << *i << endl;
 }
 }
 wcout << L"Press any key for exit" << endl;
 getchar();
 return 0;
 }
 Теперь это же надо повторить на C#... |  
						| 
								|  |  
								| « Последнее редактирование: 26-07-2012 16:37 от Dimka » |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| RXL | 
								|  | « Ответ #6 : 26-07-2012 16:41 »  |  | 
 
 Dimka, я нашел в англоязычном инете три упоминания проблемы, аналогичной твоей. Решения нигде не предложено.Зато есть полно примеров работы с OpenFileDialog - попробуй сравнить свой код, может найдешь отличие.
 |  
						| 
								|  |  
								|  |  Записан | 
 
 ... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С. |  |  | 
	| 
			| 
					
						| zubr 
								Гость
 | 
								|  | « Ответ #7 : 26-07-2012 17:07 »  |  | 
 
 Возможно тут проблема в поле openFileName.hInstance. Давно как-то что то похожее у меня было, но там я эту функцию вызывал в dll. Проблема решилась, когда я в поле .hInstance подставил .hInstance основного приложения. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #8 : 26-07-2012 17:54 »  |  | 
 
 RXL, я с этим OpenFileDialog работал неоднократно. И один раз с ним была какая-то проблема - генерировался внутренний Exception, что на что-то влияло. Теперь же рушится стек. В .NET классе я к полям структуры доступа не имею. Так что без вариантов WinAPI. Вот перевёл на C# вышеописанное. using System;using System.Collections.Generic;
 using System.Runtime.InteropServices;
 using System.Text;
 
 namespace Test
 {
 class OpenFileDialog
 {
 private const uint OFN_ALLOWMULTISELECT = 0x200;
 private const uint OFN_PATHMUSTEXIST = 0x800;
 private const uint OFN_FILEMUSTEXIST = 0x1000;
 private const uint OFN_EXPLORER = 0x80000;
 private const int BufferSize = 260000;
 
 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
 private struct OpenFileName
 {
 public uint lStructSize;
 public IntPtr hwndOwner;
 public IntPtr hInstance;
 public string lpstrFilter;
 public string lpstrCustomFilter;
 public uint nMaxCustFilter;
 public uint nFilterIndex;
 [MarshalAs(UnmanagedType.BStr)]
 public string lpstrFile;
 public uint nMaxFile;
 public string lpstrFileTitle;
 public uint nMaxFileTitle;
 public string lpstrInitialDir;
 public string lpstrTitle;
 public uint Flags;
 public ushort nFileOffset;
 public ushort nFileExtension;
 public string lpstrDefExt;
 public IntPtr lCustData;
 public IntPtr lpfnHook;
 public string lpTemplateName;
 public IntPtr pvReserved;
 public uint dwReserved;
 public uint FlagsEx;
 }
 
 [DllImport("comdlg32.dll", EntryPoint = "GetOpenFileNameW")]
 private static extern bool GetOpenFileName(ref OpenFileName openFileName);
 
 private List<string> fileNames;
 private OpenFileName openFileName;
 
 public OpenFileDialog()
 {
 this.openFileName = new OpenFileName();
 this.openFileName.dwReserved = 0;
 this.openFileName.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
 this.openFileName.FlagsEx = 0;
 this.openFileName.hInstance = IntPtr.Zero;
 this.openFileName.hwndOwner = IntPtr.Zero;
 this.openFileName.lCustData = IntPtr.Zero;
 this.openFileName.lpfnHook = IntPtr.Zero;
 this.openFileName.lpstrCustomFilter = null;
 this.openFileName.lpstrDefExt = null;
 this.openFileName.lpstrFile = new string('\0', BufferSize);
 this.openFileName.lpstrFileTitle = null;
 this.openFileName.lpstrFilter = "DICOM slices (*.dcm)\0*.dcm\0All (*.*)\0*.*\0";
 this.openFileName.lpstrInitialDir = null;
 this.openFileName.lpstrTitle = null;
 this.openFileName.lpTemplateName = null;
 this.openFileName.lStructSize = Convert.ToUInt32(Marshal.SizeOf(this.openFileName));
 this.openFileName.nFileExtension = 0;
 this.openFileName.nFileOffset = 0;
 this.openFileName.nFilterIndex = 1;
 this.openFileName.nMaxCustFilter = 0;
 this.openFileName.nMaxFile = BufferSize;
 this.openFileName.nMaxFileTitle = 0;
 this.openFileName.pvReserved = IntPtr.Zero;
 this.fileNames = new List<string>();
 }
 
 public bool ShowDialog()
 {
 bool result = GetOpenFileName(ref this.openFileName);
 if (result)
 {
 int i = 0;
 string path = string.Empty;
 string[] parts = this.openFileName.lpstrFile.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
 foreach (string part in parts)
 {
 if (path.Length == 0)
 {
 path = part;
 }
 else
 {
 string fullPath = path + "\\" + part;
 this.fileNames.Add(fullPath);
 }
 }
 if (this.fileNames.Count == 0 && path.Length > 0)
 {
 // Selected only 1 file. Its full path is stored into path.
 this.fileNames.Add(path);
 }
 }
 return result;
 }
 
 public string[] FileNames
 {
 get
 {
 return this.fileNames.ToArray();
 }
 }
 }
 
 class Program
 {
 static void Main(string[] args)
 {
 OpenFileDialog dialog = new OpenFileDialog();
 if (dialog.ShowDialog())
 {
 foreach (string fileName in dialog.FileNames)
 {
 Console.WriteLine(fileName);
 }
 }
 
 Console.WriteLine("Press any key for exit.");
 Console.ReadKey();
 }
 
 }
 
 }
 Завтра буду испытывать. |  
						| 
								|  |  
								| « Последнее редактирование: 26-07-2012 18:15 от Dimka » |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #9 : 27-07-2012 03:14 »  |  | 
 
 в АПИшном варианте из поста #5 как раз легко завалить стек - как размером буфера, так и выпрыгиванием за край этого буфера (если это происходит в недрах GetOpenFileName) я бы вот так написал         std::wstring buffer(MAX_PATH * 1000,0);
 OPENFILENAMEW openFileName={0};
 openFileName.lStructSize = sizeof(openFileName);
 openFileName.lpstrFile = &buffer[0];
 openFileName.nMaxFile = buffer.size();
 openFileName.lpstrFilter = L"DICOM slices (*.dcm)\0*.dcm\0All\0*.*\0";
 openFileName.nFilterIndex = 1;
 openFileName.Flags = OFN_ALLOWMULTISELECT | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER;
 
 BOOL result = GetOpenFileNameW(&openFileName);
 if(result != 0)
 {
 std::wstring path;
 std::list<std::wstring> files;
 
 for(int i=0; openFileName.lpstrFile[i]; i++)
 {
 std::wstring file=&openFileName.lpstrFile[i];
 i+=file.size();
 
 if(path.empty())
 {
 path = file;
 }
 else
 {
 std::wstring fullPath = std::wstring(path).append(L"\\").append(file);
 files.push_back(fullPath);
 }
 }
 
 if(files.size() == 0 && path.size() > 0)
 {
 files.push_back(path);
 }
 for(std::list<std::wstring>::iterator i = files.begin(); i != files.end(); i++)
 {
 std::wcout << *i << std::endl;
 }
 }
 std::wcout << L"Press any key for exit" << endl;
 getchar();
 return 0;
 |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #10 : 27-07-2012 06:06 »  |  | 
 
 Алексей1153++, ты хочешь сказать, что API-функция умеет грамотно писать в string? Ей же буфер нужен. В этом-то всё и дело, ради этого-то и нужно обращение к WinAPI - подставить заранее выделенный буфер достаточного размера. |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #11 : 27-07-2012 06:14 »  |  | 
 
 А, понял. Ты про то, что буфер на стеке выделяется. |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #12 : 27-07-2012 06:57 »  |  | 
 
 Не, не помогает WinAPI версия. И подставновка hInstance тоже.
 Более того, был придуман тест, на котором валится без вызова этого диалога. Значит просто звёзды так сошлись, что наблюдалась устойчивая корреляция между вызовом диалога и обрушением стека. А проблема не в диалоге.
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #13 : 27-07-2012 08:47 »  |  | 
 
 Алексей1153++, ты хочешь сказать, что API-функция умеет грамотно писать в string? Ей же буфер нужен.
 я выделил размер wstring заранее Более того, был придуман тест, на котором валится без вызова этого диалога. 
 это значит, что стек ещё раньше задет. Я тоже на такое нарывался (причём индикатором оказался именно этот диалог    )  У меня тогда, помнится, было неправильное выравнивание (пропустил #pragma(pop) после #pragma(push,1) )  после чего в одном месте кода структура была одного размера, в другом - другого (в разных файлах реализации).  Возможно ли это в шарпе допустить - я не знаю ) как это обнаружил , когда искал: в одну из функцию передаю одни значения переменных, а при входе обнаруживаю там другие |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #14 : 27-07-2012 08:53 »  |  | 
 
 Алексей1153++, на C# написан только GUI. Основная же обработка - на C++ в dll. Выравниваний в коде нету. Но что-то сломать стек может. С учётом того, что писалось это не очень-то качественно. |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #15 : 27-07-2012 08:59 »  |  | 
 
 для теста - выставь в настройках проекта выравнивание на 1 байт. Если заработает без глюков, то дело в этом |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #16 : 27-07-2012 09:48 »  |  | 
 
 Алексей1153++, мысль насчёт выравниваний оказалась полезной. Только не в той степи.    Есть выравнивание при работе с видеопамятью - выравнивание данных по степеням двойки. Валится только тогда, когда размер исходных данные не является степенью двойки. Какой-то там баг сидит. Будем копать... |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #17 : 27-07-2012 15:46 »  |  | 
 
 это может быть:1) размер текстур
 2) размер первичной поверхности
 |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	|  |