Re[4]: Выполнение функции GetClassInfoExA в C#
От: Meverik  
Дата: 08.05.13 06:52
Оценка: 6 (1)
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, Meverik, Вы писали:


M>>В C# пытаюсь работать с неуправляемым кодом DLL а конкретно с DLL написанной на Delphi содержащей форму.

M>>Все создается, формой управляю, но вот когда из Delphi еще одна форма создается,
M>>вот тут начинаются проблемы по созданию компонентов (расположенных на данной форме) основанных на стандартных оконных классах (TButton, TEdit и т.п.). Точнее объект Delphi класса создается, но
M>>когда происходит создание Windows окна компонента (непосредственно метод TWinControl.CreateWnd), то с помощью GetClassInfoA вычисляется адрес стандартного оконного класса, а этот адрес уже не тот, что при создании компонентов на первой форме и соответственно при передачи его в CreateWindowEx функция в итоге не возвращает Handle окна, что приводит к ошибке RaiseLastOSError (A call to an OS function failed). После длительного разбора "полетов" пришел вот к такой особенности C#.... И как это обойти пока не ясно....

PD>Могу предложить попробовать трюк. А именно, создать никому не нужную форму из C# до всей этой деятельности (сделать ее невидимой, конечно). Возможно, при этом вся деятельность по сабклассингу пройдет, так что создание как первой , так и второй Delphi форм будет происходить уже в условиях свершившегося сабклассинга. Поможет или нет — бог знает.


Так дело в том что первая форма создается нормально, а вот если из нее еще одну создавать.... вообщем уже не суть....

В итоге проблема решена. Для истории опишу что было:

В C# есть метод класса Application: EnableVisualStyles(); -- Этот метод включает визуальные стили приложения, что в итоге приводит к тому, что для прорисовки управляющих элементов (которые соответственно основаны на стандартных оконных классах типа BUTTON, EDIT и т.п.) необходимо использовать библиотеку comctl32.dll 6-ой версии, а по умолчанию используется comctl32.dll 5-ой версии, для отрисовки все тех же элементов управления. Так вот в Windows XP уже была добавлена возможность работать одновременно с двумя одинаковыми библиотеками разных версий, что успешно делает C#. Вот почему до создания формы в C# GetClassInfoExA возвращал один адрес оконной процедуры (которая прописана для данного оконного класса в comctl32.dll 5-ой версии), а при созданной форме уже использовал для элементов управления библиотеку comctl32.dll 6-ой версии, вот GetClassInfoExA и возвращая другой адрес, т.к. фактически классы EDIT, BUTTON и т.п. созданы в другой библиотеки. Ну а Delphi по умолчанию просто использует comctl32.dll 5-ой версии и в нем таких проблем не было.

Решение следующее (возможно можно как-то по другому, если есть идея, буду рад ознакомиться с ней): Комментим Application.EnableVisualStyles() для того, чтобы C# использовал только comctl32.dll 5-ой версии и все.... все будет работать, только визуальные компоненты отображаются уже не "красивыми" как изначально с данной опцией.... !!! НО !!! Есть, начиная с Windows XP такие файлы: Manifest называются )) Вот с помощью их описываем, что приложение должно использовать comctl32.dll 6-ой версии и C# тогда начинает во всем приложении использовать только 6-ую версию библиотеки... включая модули (DLL формы) написанные на Delphi и все управляющие элементы становятся снова "красивыми" ))

Манифест можно положить рядом с EXE файлом программы (с названием: [имя файла программы].exe.Manifest) или добавить его в C# проект и в настройка проекта выбрать данный файл манифеста, чтобы он присутствовал в самом EXE файле программы, что я и сделал.

Манифест у меня такой:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
      <application> 
        <!--The ID below indicates application support for Windows Vista --> 
          <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> 
        <!--The ID below indicates application support for Windows 7 --> 
          <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> 
      </application> 
    </compatibility>

<assemblyIdentity
   name="Название моей программы"
   processorArchitecture="*"
   version="1.0.0.0"
   type="win32"/>
<description>Описание моей программы</description>
<dependency>
   <dependentAssembly>
       <assemblyIdentity
           type="win32"
           name="Microsoft.Windows.Common-Controls"
           version="6.0.0.0"
           processorArchitecture="*"
           publicKeyToken="6595b64144ccf1df"
           language="*"
       />
   </dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
      <security>
      <requestedPrivileges>
        <requestedExecutionLevel
          level="asInvoker"
          uiAccess="false"/>
      </requestedPrivileges>
    </security>
   </trustInfo>
</assembly>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.